From 07e462a1b67b5a7dec8f38ba89454daf592fbf96 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 06:22:07 +0000 Subject: [PATCH] refactor: extract getActionInput() helper for hyphen/underscore input normalization The two-key lookup pattern for normalizing GitHub Actions inputs (handling both INPUT_X and INPUT_X-HYPHEN forms) was introduced in PR #24823 and repeated in three places: index.js, action_setup_otlp.cjs, and action_conclusion_otlp.cjs. Extract a getActionInput(name) helper in action_input_utils.cjs that: - Checks both the underscore (standard) and hyphen (some runner versions) forms - Trims whitespace from the result (aligning with GitHub Actions conventions) - Documents the rationale once, rather than repeating it at each call site This reduces code duplication, removes repetitive comments, and makes it easy to add new inputs with the same normalization in the future. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- actions/setup/index.js | 29 +++------- actions/setup/js/action_conclusion_otlp.cjs | 5 +- actions/setup/js/action_input_utils.cjs | 20 +++++++ actions/setup/js/action_input_utils.test.cjs | 57 ++++++++++++++++++++ actions/setup/js/action_setup_otlp.cjs | 16 ++---- 5 files changed, 91 insertions(+), 36 deletions(-) create mode 100644 actions/setup/js/action_input_utils.cjs create mode 100644 actions/setup/js/action_input_utils.test.cjs 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; }