Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ This default configuration:
- Runs all Buf checks (`build`, `lint`, `format`, and `breaking`), posting a [summary comment](https://buf.build/docs/bsr/ci-cd/github-actions/#configure-summary-comment) for any pull request.
- Archives corresponding [labels](https://buf.build/docs/bsr/commits-labels/#labels) in the BSR when you delete a Git branch or tag.

If BSR login intermittently fails because the registry is slow to respond, you can tune the login retry behavior:

```yaml
- uses: bufbuild/buf-action@v1
with:
token: ${{ secrets.BUF_TOKEN }}
login_retries: 5
login_retry_delay_seconds: 10
```

`login_retries` counts retries after the initial login attempt. `login_retries` and `login_retry_delay_seconds` default to `5` and `10` respectively.
Comment thread
aiell0 marked this conversation as resolved.

## Documentation

For comprehensive configuration options, advanced workflows, and detailed examples, see the [Buf GitHub Action Documentation](https://buf.build/docs/bsr/ci-cd/github-actions).
Expand Down
10 changes: 10 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ inputs:
Domain for logging into the BSR, enterprise only.
required: false
default: "buf.build"
login_retries:
description: |-
Number of times to retry logging in to the BSR after the initial attempt fails.
required: false
default: "5"
login_retry_delay_seconds:
description: |-
Number of seconds to wait between BSR login attempts.
required: false
default: "10"
github_actor:
description: |-
GitHub actor for API requests.
Expand Down
46 changes: 42 additions & 4 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101817,6 +101817,8 @@ function getInputs() {
token: lib_core.getInput("token") || getEnv("BUF_TOKEN"),
checksum: lib_core.getInput("checksum"),
domain: lib_core.getInput("domain"),
login_retries: getNonNegativeIntegerInput("login_retries", 5),
login_retry_delay_seconds: getNonNegativeIntegerInput("login_retry_delay_seconds", 10),
setup_only: lib_core.getBooleanInput("setup_only"),
pr_comment: lib_core.getBooleanInput("pr_comment"),
github_actor: lib_core.getInput("github_actor"),
Expand Down Expand Up @@ -101865,6 +101867,18 @@ function getInputs() {
}
return inputs;
}
function getNonNegativeIntegerInput(name, defaultValue) {
const value = lib_core.getInput(name);
if (value === "") {
return defaultValue;
}
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed < 0) {
lib_core.warning(`Invalid value for ${name}: ${value}. Expected a non-negative integer, using default ${defaultValue}.`);
return defaultValue;
}
return parsed;
}
// getEnv returns the case insensitive value of the environment variable.
// Prefers the lowercase version of the variable if it exists.
function getEnv(name) {
Expand Down Expand Up @@ -106081,15 +106095,39 @@ async function runWorkflow(bufPath, inputs, moduleNames) {
}
// login logs in to the Buf registry, storing credentials.
async function login(bufPath, inputs) {
const { token, domain } = inputs;
const { token, domain, login_retries, login_retry_delay_seconds } = inputs;
if (token == "") {
lib_core.debug("Skipping login, no token provided");
return;
}
lib_core.debug(`Logging in to ${domain}`);
await lib_exec.exec(bufPath, ["registry", "login", domain, "--token-stdin"], {
input: Buffer.from(token + "\n"),
});
const args = ["registry", "login", domain, "--token-stdin"];
const input = Buffer.from(`${token}\n`);
const maxAttempts = login_retries + 1;
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const exitCode = await lib_exec.exec(bufPath, args, {
input,
silent: attempt < maxAttempts,
});
if (exitCode == 0) {
return;
}
lastError = new Error(`buf registry login exited with code ${exitCode}`);
}
catch (error) {
lastError = error;
}
if (attempt == maxAttempts) {
break;
}
lib_core.warning(`Login to ${domain} failed (attempt ${attempt} of ${maxAttempts}). Retrying in ${login_retry_delay_seconds} seconds.`);
await new Promise((resolve) => setTimeout(resolve, login_retry_delay_seconds * 1000));
}
throw lastError instanceof Error
? lastError
: new Error(`Failed to log in to ${domain}`);
}
// build runs the "buf build" step.
async function build(bufPath, inputs) {
Expand Down
14 changes: 14 additions & 0 deletions dist/post/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60470,6 +60470,8 @@ function getInputs() {
token: core.getInput("token") || getEnv("BUF_TOKEN"),
checksum: core.getInput("checksum"),
domain: core.getInput("domain"),
login_retries: getNonNegativeIntegerInput("login_retries", 5),
login_retry_delay_seconds: getNonNegativeIntegerInput("login_retry_delay_seconds", 10),
setup_only: core.getBooleanInput("setup_only"),
pr_comment: core.getBooleanInput("pr_comment"),
github_actor: core.getInput("github_actor"),
Expand Down Expand Up @@ -60518,6 +60520,18 @@ function getInputs() {
}
return inputs;
}
function getNonNegativeIntegerInput(name, defaultValue) {
const value = core.getInput(name);
if (value === "") {
return defaultValue;
}
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed < 0) {
core.warning(`Invalid value for ${name}: ${value}. Expected a non-negative integer, using default ${defaultValue}.`);
return defaultValue;
}
return parsed;
}
// getEnv returns the case insensitive value of the environment variable.
// Prefers the lowercase version of the variable if it exists.
function getEnv(name) {
Expand Down
22 changes: 22 additions & 0 deletions src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface Inputs {
checksum: string;
token: string;
domain: string;
login_retries: number;
login_retry_delay_seconds: number;
setup_only: boolean;
pr_comment: boolean;
github_actor: string;
Expand Down Expand Up @@ -56,6 +58,11 @@ export function getInputs(): Inputs {
token: core.getInput("token") || getEnv("BUF_TOKEN"),
checksum: core.getInput("checksum"),
domain: core.getInput("domain"),
login_retries: getNonNegativeIntegerInput("login_retries", 5),
login_retry_delay_seconds: getNonNegativeIntegerInput(
"login_retry_delay_seconds",
10,
),
setup_only: core.getBooleanInput("setup_only"),
pr_comment: core.getBooleanInput("pr_comment"),
github_actor: core.getInput("github_actor"),
Expand Down Expand Up @@ -107,6 +114,21 @@ export function getInputs(): Inputs {
return inputs;
}

function getNonNegativeIntegerInput(name: string, defaultValue: number): number {
const value = core.getInput(name);
if (value === "") {
return defaultValue;
}
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed < 0) {
core.warning(
`Invalid value for ${name}: ${value}. Expected a non-negative integer, using default ${defaultValue}.`,
);
return defaultValue;
}
return parsed;
}

// getEnv returns the case insensitive value of the environment variable.
// Prefers the lowercase version of the variable if it exists.
export function getEnv(name: string): string {
Expand Down
35 changes: 31 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,42 @@ async function runWorkflow(

// login logs in to the Buf registry, storing credentials.
async function login(bufPath: string, inputs: Inputs) {
const { token, domain } = inputs;
const { token, domain, login_retries, login_retry_delay_seconds } = inputs;
if (token == "") {
core.debug("Skipping login, no token provided");
return;
}
core.debug(`Logging in to ${domain}`);
await exec.exec(bufPath, ["registry", "login", domain, "--token-stdin"], {
input: Buffer.from(token + "\n"),
});
const args = ["registry", "login", domain, "--token-stdin"];
const input = Buffer.from(`${token}\n`);
const maxAttempts = login_retries + 1;
let lastError: unknown;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const exitCode = await exec.exec(bufPath, args, {
input,
silent: attempt < maxAttempts,
});
if (exitCode == 0) {
return;
}
lastError = new Error(`buf registry login exited with code ${exitCode}`);
} catch (error: unknown) {
lastError = error;
}
if (attempt == maxAttempts) {
break;
}
core.warning(
`Login to ${domain} failed (attempt ${attempt} of ${maxAttempts}). Retrying in ${login_retry_delay_seconds} seconds.`,
);
await new Promise((resolve) =>
setTimeout(resolve, login_retry_delay_seconds * 1000),
);
}
throw lastError instanceof Error
? lastError
: new Error(`Failed to log in to ${domain}`);
}

// build runs the "buf build" step.
Expand Down
Loading