diff --git a/actions/setup/index.js b/actions/setup/index.js index be5d12d0219..437c6499946 100644 --- a/actions/setup/index.js +++ b/actions/setup/index.js @@ -3,32 +3,17 @@ const { spawnSync } = require("child_process"); const path = require("path"); +const { getActionInput } = require("./js/action_input_utils.cjs"); // Record start time for the OTLP span before any setup work begins. const setupStartMs = Date.now(); -// GitHub Actions sets INPUT_* env vars for JavaScript actions by converting -// input names to uppercase and replacing hyphens with underscores. Explicitly -// normalize inputs with hyphens in their names because some runner versions -// preserve the original hyphen instead of converting it to an underscore. -const safeOutputCustomTokens = - process.env["INPUT_SAFE_OUTPUT_CUSTOM_TOKENS"] || - process.env["INPUT_SAFE-OUTPUT-CUSTOM-TOKENS"] || - "false"; - -// Normalize trace-id input: handle both INPUT_TRACE_ID (underscore, standard) -// and INPUT_TRACE-ID (hyphen, used by some runner versions). -const inputTraceId = - process.env["INPUT_TRACE_ID"] || - process.env["INPUT_TRACE-ID"] || - ""; - -// Normalize job-name input: handle both INPUT_JOB_NAME (underscore, standard) -// and INPUT_JOB-NAME (hyphen, used by some runner versions). -const inputJobName = - process.env["INPUT_JOB_NAME"] || - process.env["INPUT_JOB-NAME"] || - ""; +// GitHub Actions converts input names to INPUT_, but some +// runner versions preserve the original hyphen form. getActionInput() handles +// both forms automatically. +const safeOutputCustomTokens = getActionInput("SAFE_OUTPUT_CUSTOM_TOKENS") || "false"; +const inputTraceId = getActionInput("TRACE_ID"); +const inputJobName = getActionInput("JOB_NAME"); const result = spawnSync(path.join(__dirname, "setup.sh"), [], { stdio: "inherit", diff --git a/actions/setup/js/action_conclusion_otlp.cjs b/actions/setup/js/action_conclusion_otlp.cjs index 3fa4b0c3c98..63a4085cf5c 100644 --- a/actions/setup/js/action_conclusion_otlp.cjs +++ b/actions/setup/js/action_conclusion_otlp.cjs @@ -30,6 +30,7 @@ */ const sendOtlpSpan = require("./send_otlp_span.cjs"); +const { getActionInput } = require("./action_input_utils.cjs"); /** * Send the OTLP job-conclusion span. Non-fatal: all errors are silently @@ -48,9 +49,7 @@ async function run() { const rawJobStartMs = parseInt(process.env.GITHUB_AW_OTEL_JOB_START_MS || "0", 10); const startMs = rawJobStartMs > 0 ? rawJobStartMs : undefined; - // Normalize job-name input: handle both INPUT_JOB_NAME (underscore, standard) - // and INPUT_JOB-NAME (hyphen, used by some runner versions). - const jobName = (process.env.INPUT_JOB_NAME || process.env["INPUT_JOB-NAME"] || "").trim(); + const jobName = getActionInput("JOB_NAME"); const spanName = jobName ? `gh-aw.${jobName}.conclusion` : "gh-aw.job.conclusion"; console.log(`[otlp] sending conclusion span "${spanName}" to ${endpoint}`); diff --git a/actions/setup/js/action_input_utils.cjs b/actions/setup/js/action_input_utils.cjs new file mode 100644 index 00000000000..5db08e77260 --- /dev/null +++ b/actions/setup/js/action_input_utils.cjs @@ -0,0 +1,20 @@ +// @ts-check +"use strict"; + +/** + * Read a GitHub Actions input value, handling both the standard underscore form + * (INPUT_) and the hyphen form (INPUT_) preserved by some runner versions. + * + * GitHub Actions converts input names to INPUT_ by default, but + * some runner versions preserve the original hyphen from the input name. Checking + * both forms ensures the value is resolved regardless of the runner version. + * + * @param {string} name - Input name in UPPER_UNDERSCORE form (e.g. "JOB_NAME") + * @returns {string} Trimmed input value, or "" if not set. + */ +function getActionInput(name) { + const hyphenName = name.replace(/_/g, "-"); + return (process.env[`INPUT_${name}`] || process.env[`INPUT_${hyphenName}`] || "").trim(); +} + +module.exports = { getActionInput }; diff --git a/actions/setup/js/action_input_utils.test.cjs b/actions/setup/js/action_input_utils.test.cjs new file mode 100644 index 00000000000..9d66236f4b2 --- /dev/null +++ b/actions/setup/js/action_input_utils.test.cjs @@ -0,0 +1,57 @@ +// @ts-check +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { createRequire } from "module"; + +const req = createRequire(import.meta.url); +const { getActionInput } = req("./action_input_utils.cjs"); + +describe("getActionInput", () => { + let originalEnv; + + beforeEach(() => { + originalEnv = { + INPUT_JOB_NAME: process.env.INPUT_JOB_NAME, + "INPUT_JOB-NAME": process.env["INPUT_JOB-NAME"], + }; + delete process.env.INPUT_JOB_NAME; + delete process.env["INPUT_JOB-NAME"]; + }); + + afterEach(() => { + if (originalEnv.INPUT_JOB_NAME !== undefined) { + process.env.INPUT_JOB_NAME = originalEnv.INPUT_JOB_NAME; + } else { + delete process.env.INPUT_JOB_NAME; + } + if (originalEnv["INPUT_JOB-NAME"] !== undefined) { + process.env["INPUT_JOB-NAME"] = originalEnv["INPUT_JOB-NAME"]; + } else { + delete process.env["INPUT_JOB-NAME"]; + } + }); + + it("returns the underscore form value when set", () => { + process.env.INPUT_JOB_NAME = "agent"; + expect(getActionInput("JOB_NAME")).toBe("agent"); + }); + + it("returns the hyphen form value when only the hyphen form is set", () => { + process.env["INPUT_JOB-NAME"] = "agent"; + expect(getActionInput("JOB_NAME")).toBe("agent"); + }); + + it("prefers the underscore form over the hyphen form", () => { + process.env.INPUT_JOB_NAME = "underscore-value"; + process.env["INPUT_JOB-NAME"] = "hyphen-value"; + expect(getActionInput("JOB_NAME")).toBe("underscore-value"); + }); + + it("trims whitespace from the returned value", () => { + process.env.INPUT_JOB_NAME = " agent "; + expect(getActionInput("JOB_NAME")).toBe("agent"); + }); + + it("returns empty string when neither form is set", () => { + expect(getActionInput("JOB_NAME")).toBe(""); + }); +}); diff --git a/actions/setup/js/action_setup_otlp.cjs b/actions/setup/js/action_setup_otlp.cjs index 22fc3e3888a..8363d6b2f60 100644 --- a/actions/setup/js/action_setup_otlp.cjs +++ b/actions/setup/js/action_setup_otlp.cjs @@ -28,6 +28,7 @@ const path = require("path"); const { appendFileSync } = require("fs"); const { nowMs } = require("./performance_now.cjs"); +const { getActionInput } = require("./action_input_utils.cjs"); /** * Send the OTLP job-setup span and propagate trace context via GITHUB_OUTPUT / @@ -48,24 +49,17 @@ async function run() { // Explicitly read INPUT_TRACE_ID and pass it as options.traceId so the // activation job's trace ID is used even when process.env propagation // through GitHub Actions expression evaluation is unreliable. - // Also handle INPUT_TRACE-ID (with hyphen) in case the runner preserves - // the original input name hyphen instead of converting it to an underscore. - const inputTraceId = (process.env.INPUT_TRACE_ID || process.env["INPUT_TRACE-ID"] || "").trim().toLowerCase(); + const inputTraceId = getActionInput("TRACE_ID").toLowerCase(); if (inputTraceId) { console.log(`[otlp] INPUT_TRACE_ID=${inputTraceId} (will reuse activation trace)`); } else { console.log("[otlp] INPUT_TRACE_ID not set, a new trace ID will be generated"); } - // Normalize job-name input: handle both INPUT_JOB_NAME (underscore, standard) - // and INPUT_JOB-NAME (hyphen, used by some runner versions). Mirror the same - // two-key lookup that INPUT_TRACE_ID uses above so script-mode invocations - // (setup.sh → node action_setup_otlp.cjs) always resolve the job name even - // when the runner preserves the original hyphen in the env var name. - const inputJobName = (process.env.INPUT_JOB_NAME || process.env["INPUT_JOB-NAME"] || "").trim(); + // Normalize to the canonical underscore form so sendJobSetupSpan (which + // reads process.env.INPUT_JOB_NAME) always finds the value. + const inputJobName = getActionInput("JOB_NAME"); if (inputJobName) { - // Normalise to the canonical underscore form so sendJobSetupSpan (which - // reads process.env.INPUT_JOB_NAME) always finds the value. process.env.INPUT_JOB_NAME = inputJobName; }