Skip to content
Merged
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
2 changes: 1 addition & 1 deletion actions/setup/js/workflow_metadata_helpers.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function getWorkflowMetadata(owner, repo) {
* cross-repo effectiveContext) so that footer links point back to the actual workflow
* run regardless of which repository the output action targets.
*
* @param {any} ctx - GitHub Actions context (provides serverUrl and runId)
* @param {{ serverUrl?: string, runId: number | string }} ctx - GitHub Actions context (provides serverUrl and runId)
* @param {{ owner: string, repo: string }} workflowRepo - The repository that owns the workflow run
* @returns {string} The full workflow run URL
*/
Expand Down
58 changes: 51 additions & 7 deletions actions/setup/js/workflow_metadata_helpers.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,27 @@ describe("getWorkflowMetadata", () => {
expect(metadata.runId).toBe(0);
expect(metadata.runUrl).toBe("https://github.com/test-owner/test-repo/actions/runs/0");
});

it("should prefer context.serverUrl over GITHUB_SERVER_URL env var", () => {
global.context = {
runId: 42,
serverUrl: "https://context-server.example.com",
};
process.env.GITHUB_SERVER_URL = "https://env-server.example.com";

const metadata = getWorkflowMetadata("owner", "repo");

expect(metadata.runUrl).toBe("https://context-server.example.com/owner/repo/actions/runs/42");
});

it("should fall back to https://github.com when no server URL sources are available", () => {
global.context = { runId: 7 };
delete process.env.GITHUB_SERVER_URL;

const metadata = getWorkflowMetadata("my-owner", "my-repo");

expect(metadata.runUrl).toBe("https://github.com/my-owner/my-repo/actions/runs/7");
});
});

describe("buildWorkflowRunUrl", () => {
Expand All @@ -106,13 +127,16 @@ describe("buildWorkflowRunUrl", () => {
it("should fall back to GITHUB_SERVER_URL when context.serverUrl is absent", () => {
const originalEnv = process.env.GITHUB_SERVER_URL;
process.env.GITHUB_SERVER_URL = "https://ghes.example.com";
const ctx = { runId: 99 };
const url = buildWorkflowRunUrl(ctx, { owner: "ent-owner", repo: "ent-repo" });
expect(url).toBe("https://ghes.example.com/ent-owner/ent-repo/actions/runs/99");
if (originalEnv === undefined) {
delete process.env.GITHUB_SERVER_URL;
} else {
process.env.GITHUB_SERVER_URL = originalEnv;
try {
const ctx = { runId: 99 };
const url = buildWorkflowRunUrl(ctx, { owner: "ent-owner", repo: "ent-repo" });
expect(url).toBe("https://ghes.example.com/ent-owner/ent-repo/actions/runs/99");
} finally {
if (originalEnv === undefined) {
delete process.env.GITHUB_SERVER_URL;
} else {
process.env.GITHUB_SERVER_URL = originalEnv;
}
}
});

Expand All @@ -125,4 +149,24 @@ describe("buildWorkflowRunUrl", () => {
expect(url).not.toContain("cross-owner");
expect(url).not.toContain("cross-repo");
});

it("should fall back to https://github.com when no server URL sources are available", () => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/zoom-out] This test manually saves/restores GITHUB_SERVER_URL, but the cleanup at lines 158–162 is not guarded by try-finally. If the assertion on line 155 throws, cleanup is skipped and the deleted env var leaks into subsequent tests in this block.

�� Suggested: add lifecycle hooks to the buildWorkflowRunUrl describe block

The getWorkflowMetadata describe block (lines 5–118) already establishes the right pattern with beforeEach/afterEach. Applying the same to buildWorkflowRunUrl would let individual tests drop their manual save/restore entirely:

describe("buildWorkflowRunUrl", () => {
  let savedServerUrl;

  beforeEach(() => {
    savedServerUrl = process.env.GITHUB_SERVER_URL;
  });

  afterEach(() => {
    if (savedServerUrl === undefined) {
      delete process.env.GITHUB_SERVER_URL;
    } else {
      process.env.GITHUB_SERVER_URL = savedServerUrl;
    }
  });

  // tests can now freely mutate process.env.GITHUB_SERVER_URL
});

As a smaller improvement, the existing if (originalEnv === undefined) { delete process.env.GITHUB_SERVER_URL; } branch (line 158) is a no-op — the var was already deleted at line 152 — so the branch can be simplified to just else { process.env.GITHUB_SERVER_URL = originalEnv; }.

const originalEnv = process.env.GITHUB_SERVER_URL;
delete process.env.GITHUB_SERVER_URL;
try {
const url = buildWorkflowRunUrl({ runId: 1 }, { owner: "owner", repo: "repo" });
expect(url).toBe("https://github.com/owner/repo/actions/runs/1");
} finally {
if (originalEnv === undefined) {
delete process.env.GITHUB_SERVER_URL;
} else {
process.env.GITHUB_SERVER_URL = originalEnv;
}
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Env-var cleanup runs after the assertion — state leaks on test failure.

If expect(url).toBe(...) throws, the if/else restore block below it is never reached and GITHUB_SERVER_URL stays deleted for all tests that run afterward in the same process.

�� Suggested fix — wrap in try/finally
it("should fall back to https://github.com when no server URL sources are available", () => {
  const originalEnv = process.env.GITHUB_SERVER_URL;
  delete process.env.GITHUB_SERVER_URL;
  try {
    const url = buildWorkflowRunUrl({ runId: 1 }, { owner: "owner", repo: "repo" });
    expect(url).toBe("https://github.com/owner/repo/actions/runs/1");
  } finally {
    if (originalEnv === undefined) {
      delete process.env.GITHUB_SERVER_URL;
    } else {
      process.env.GITHUB_SERVER_URL = originalEnv;
    }
  }
});

Alternatively, add a beforeEach/afterEach to the buildWorkflowRunUrl describe block that snapshots and restores process.env (matching the pattern already used in the getWorkflowMetadata suite above). The existing test at line 127 has the same fragility and would benefit from the same fix.

});
Comment on lines +153 to +166

it("should handle runId of 0", () => {
const url = buildWorkflowRunUrl({ serverUrl: "https://github.com", runId: 0 }, { owner: "owner", repo: "repo" });
expect(url).toBe("https://github.com/owner/repo/actions/runs/0");
});
});
Loading