Retries on oidc. 152

This commit is contained in:
Colin McDonnell
2025-12-22 14:33:18 -08:00
parent 2dea842981
commit 5353d80388
4 changed files with 41 additions and 12 deletions
+35 -6
View File
@@ -45360,14 +45360,14 @@ var require_retry_agent = __commonJS({
this.#options = options; this.#options = options;
} }
dispatch(opts, handler2) { dispatch(opts, handler2) {
const retry = new RetryHandler({ const retry2 = new RetryHandler({
...opts, ...opts,
retryOptions: this.#options retryOptions: this.#options
}, { }, {
dispatch: this.#agent.dispatch.bind(this.#agent), dispatch: this.#agent.dispatch.bind(this.#agent),
handler: handler2 handler: handler2
}); });
return this.#agent.dispatch(opts, retry); return this.#agent.dispatch(opts, retry2);
} }
close() { close() {
return this.#agent.close(); return this.#agent.close();
@@ -83328,7 +83328,7 @@ function query({
// package.json // package.json
var package_default = { var package_default = {
name: "@pullfrog/action", name: "@pullfrog/action",
version: "0.0.151", version: "0.0.152",
type: "module", type: "module",
files: [ files: [
"index.js", "index.js",
@@ -92866,6 +92866,35 @@ import { pipeline } from "node:stream/promises";
// utils/github.ts // utils/github.ts
var core2 = __toESM(require_core(), 1); var core2 = __toESM(require_core(), 1);
import { createSign } from "node:crypto"; import { createSign } from "node:crypto";
// utils/retry.ts
var defaultShouldRetry = (error41) => {
if (!(error41 instanceof Error)) return false;
return error41.name === "AbortError" || error41.message.includes("fetch failed") || error41.message.includes("ECONNRESET") || error41.message.includes("ETIMEDOUT");
};
async function retry(fn2, options = {}) {
const maxAttempts = options.maxAttempts ?? 3;
const delayMs = options.delayMs ?? 1e3;
const shouldRetry = options.shouldRetry ?? defaultShouldRetry;
const label = options.label ?? "operation";
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn2();
} catch (error41) {
lastError = error41;
if (attempt === maxAttempts || !shouldRetry(error41)) {
throw error41;
}
const delay2 = delayMs * attempt;
log.warning(`\xBB ${label} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay2}ms...`);
await new Promise((resolve2) => setTimeout(resolve2, delay2));
}
}
throw lastError;
}
// utils/github.ts
function isGitHubActionsEnvironment() { function isGitHubActionsEnvironment() {
return Boolean(process.env.GITHUB_ACTIONS); return Boolean(process.env.GITHUB_ACTIONS);
} }
@@ -92998,7 +93027,7 @@ async function acquireTokenViaGitHubApp() {
} }
async function acquireNewToken() { async function acquireNewToken() {
if (isGitHubActionsEnvironment()) { if (isGitHubActionsEnvironment()) {
return await acquireTokenViaOIDC(); return await retry(() => acquireTokenViaOIDC(), { label: "token exchange" });
} else { } else {
return await acquireTokenViaGitHubApp(); return await acquireTokenViaGitHubApp();
} }
@@ -123027,10 +123056,10 @@ async function checkoutPrBranch(params) {
const remoteName = `pr-${pullNumber}`; const remoteName = `pr-${pullNumber}`;
const forkUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`; const forkUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`;
try { try {
$("git", ["remote", "add", remoteName, forkUrl]); $("git", ["remote", "add", remoteName, forkUrl], { log: false });
log.debug(`\u{1F4CC} added remote '${remoteName}' for fork ${headRepo.full_name}`); log.debug(`\u{1F4CC} added remote '${remoteName}' for fork ${headRepo.full_name}`);
} catch { } catch {
$("git", ["remote", "set-url", remoteName, forkUrl]); $("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
log.debug(`\u{1F4CC} updated remote '${remoteName}' for fork ${headRepo.full_name}`); log.debug(`\u{1F4CC} updated remote '${remoteName}' for fork ${headRepo.full_name}`);
} }
$("git", ["config", `branch.${localBranch}.pushRemote`, remoteName]); $("git", ["config", `branch.${localBranch}.pushRemote`, remoteName]);
+3 -3
View File
@@ -107,13 +107,13 @@ export async function checkoutPrBranch(
const remoteName = `pr-${pullNumber}`; const remoteName = `pr-${pullNumber}`;
const forkUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`; const forkUrl = `https://x-access-token:${token}@github.com/${headRepo.full_name}.git`;
// add fork as a named remote (ignore error if already exists) // add fork as a named remote (suppress logging to avoid "error: remote already exists" spam)
try { try {
$("git", ["remote", "add", remoteName, forkUrl]); $("git", ["remote", "add", remoteName, forkUrl], { log: false });
log.debug(`📌 added remote '${remoteName}' for fork ${headRepo.full_name}`); log.debug(`📌 added remote '${remoteName}' for fork ${headRepo.full_name}`);
} catch { } catch {
// remote already exists, update its URL // remote already exists, update its URL
$("git", ["remote", "set-url", remoteName, forkUrl]); $("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
log.debug(`📌 updated remote '${remoteName}' for fork ${headRepo.full_name}`); log.debug(`📌 updated remote '${remoteName}' for fork ${headRepo.full_name}`);
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@pullfrog/action", "name": "@pullfrog/action",
"version": "0.0.151", "version": "0.0.152",
"type": "module", "type": "module",
"files": [ "files": [
"index.js", "index.js",
+2 -2
View File
@@ -1,6 +1,7 @@
import { createSign } from "node:crypto"; import { createSign } from "node:crypto";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { log } from "./cli.ts"; import { log } from "./cli.ts";
import { retry } from "./retry.ts";
export interface InstallationToken { export interface InstallationToken {
token: string; token: string;
@@ -56,7 +57,6 @@ async function acquireTokenViaOIDC(): Promise<string> {
log.info("» exchanging OIDC token for installation token..."); log.info("» exchanging OIDC token for installation token...");
// Add timeout to prevent long waits (30 seconds)
const timeoutMs = 30000; const timeoutMs = 30000;
const controller = new AbortController(); const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs); const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -234,7 +234,7 @@ async function acquireTokenViaGitHubApp(): Promise<string> {
async function acquireNewToken(): Promise<string> { async function acquireNewToken(): Promise<string> {
if (isGitHubActionsEnvironment()) { if (isGitHubActionsEnvironment()) {
return await acquireTokenViaOIDC(); return await retry(() => acquireTokenViaOIDC(), { label: "token exchange" });
} else { } else {
return await acquireTokenViaGitHubApp(); return await acquireTokenViaGitHubApp();
} }