fix: use GITHUB_RUN_NUMBER for Forgejo job URLs and pin Bun version in CI

Forgejo uses the per-repo sequential run index (GITHUB_RUN_NUMBER) in
action URLs, not the internal DB run ID (GITHUB_RUN_ID). This caused
"View job" links to return 404. Fixed in all 4 URL construction sites:
create-initial comment, update-comment-link, and both prompt generators.

Also pins Bun to 1.2.21 in CI — Bun 1.3.9 broke spyOn(fs, ...) which
failed 18 upstream image-downloader tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vlad MocanuandClaude Opus 4.6 committed 2026-02-25 21:07:40 +02:00
1 parent 6ebfb4914f
commit 23f15aecb9
6 files changed
+109 -10

No files matched your search

+32 -6
View File
@@ -13,6 +13,11 @@ concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
# Pin Bun version across all jobs. Bun 1.3.x broke spyOn(fs, ...) in tests.
# Bump this when upstream tests are updated for newer Bun versions.
env:
BUN_VERSION: "1.2.21"
jobs:
test:
runs-on: grunt
@@ -25,9 +30,16 @@ jobs:
- name: Install Bun
run: |
if command -v bun &> /dev/null; then
echo "Bun already installed: $(bun --version)"
INSTALLED=$(bun --version)
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
echo "Bun $BUN_VERSION already installed"
else
curl -fsSL https://bun.sh/install | bash
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
else
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
@@ -56,9 +68,16 @@ jobs:
- name: Install Bun
run: |
if command -v bun &> /dev/null; then
echo "Bun already installed: $(bun --version)"
INSTALLED=$(bun --version)
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
echo "Bun $BUN_VERSION already installed"
else
curl -fsSL https://bun.sh/install | bash
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
else
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
@@ -79,9 +98,16 @@ jobs:
- name: Install Bun
run: |
if command -v bun &> /dev/null; then
echo "Bun already installed: $(bun --version)"
INSTALLED=$(bun --version)
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
echo "Bun $BUN_VERSION already installed"
else
curl -fsSL https://bun.sh/install | bash
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
else
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
fi
+12 -2
View File
@@ -20,6 +20,8 @@ import {
import type { ParsedGitHubContext } from "../github/context";
import type { CommonFields, PreparedContext, EventData } from "./types";
import { GITHUB_SERVER_URL } from "../github/api/config";
import { detectPlatform } from "../platform/detector";
import { getForgejoRunIndex } from "../forgejo/comment-logic";
import { extractUserRequest } from "../utils/extract-user-request";
export type { CommonFields, PreparedContext } from "./types";
@@ -525,7 +527,11 @@ Images from comments have been saved to disk. Paths are in the formatted content
: "No description provided";
const entityType = eventData.isPR ? "pull request" : "issue";
const jobUrl = `${GITHUB_SERVER_URL}/${context.repository}/actions/runs/${process.env.GITHUB_RUN_ID}`;
const runIdentifier =
detectPlatform() === "forgejo"
? getForgejoRunIndex()
: process.env.GITHUB_RUN_ID;
const jobUrl = `${GITHUB_SERVER_URL}/${context.repository}/actions/runs/${runIdentifier}`;
let promptContent = `You were tagged on a GitHub ${entityType} via "${context.triggerPhrase}". Read the request and decide how to help.
@@ -624,6 +630,10 @@ export function generateDefaultPrompt(
const { eventData } = context;
const { eventType, triggerContext } = getEventTypeAndContext(context);
const runIdentifier =
detectPlatform() === "forgejo"
? getForgejoRunIndex()
: process.env.GITHUB_RUN_ID;
const formattedContext = formatContext(contextData, eventData.isPR);
const formattedComments = formatComments(comments, imageUrlMap);
@@ -831,7 +841,7 @@ ${
- Display the todo list as a checklist in the GitHub comment and mark things off as you go.
- REPOSITORY SETUP INSTRUCTIONS: The repository's CLAUDE.md file(s) contain critical repo-specific setup instructions, development guidelines, and preferences. Always read and follow these files, particularly the root CLAUDE.md, as they provide essential context for working with the codebase effectively.
- Use h3 headers (###) for section titles in your comments, not h1 headers (#).
- Your comment must always include the job run link in the format "[View job run](${GITHUB_SERVER_URL}/${context.repository}/actions/runs/${process.env.GITHUB_RUN_ID})" at the bottom of your response (branch link if there is one should also be included there).
- Your comment must always include the job run link in the format "[View job run](${GITHUB_SERVER_URL}/${context.repository}/actions/runs/${runIdentifier})" at the bottom of your response (branch link if there is one should also be included there).
CAPABILITIES AND LIMITATIONS:
When users ask you to do something, be aware of what you can and cannot do. This section helps you understand how to respond when users request actions outside your scope.
+4 -1
View File
@@ -10,6 +10,7 @@ import {
import {
updateForgejoCommentBody,
createForgejoPrCompareUrl,
getForgejoRunIndex,
} from "../forgejo/comment-logic";
import { detectPlatform } from "../platform/detector";
import {
@@ -54,7 +55,9 @@ export async function updateCommentLink(
const platform = detectPlatform();
const serverUrl = GITHUB_SERVER_URL;
const jobUrl = `${serverUrl}/${owner}/${repo}/actions/runs/${process.env.GITHUB_RUN_ID}`;
const runIdentifier =
platform === "forgejo" ? getForgejoRunIndex() : process.env.GITHUB_RUN_ID;
const jobUrl = `${serverUrl}/${owner}/${repo}/actions/runs/${runIdentifier}`;
let comment;
let isPRReviewComment = false;
+18
View File
@@ -34,6 +34,24 @@ function getServerUrl(): string {
return process.env.GITHUB_SERVER_URL || "https://github.com";
}
// ---------------------------------------------------------------------------
// Run index helper
// ---------------------------------------------------------------------------
/**
* Get the run identifier for Forgejo URLs.
*
* Forgejo uses the per-repo sequential run index in URLs (`/actions/runs/{index}`),
* not the internal database run ID. The Forgejo runner sets:
* - GITHUB_RUN_ID = internal DB primary key (e.g. 11943)
* - GITHUB_RUN_NUMBER = per-repo sequential index (e.g. 661)
*
* GitHub uses GITHUB_RUN_ID in URLs, but Forgejo uses GITHUB_RUN_NUMBER.
*/
export function getForgejoRunIndex(): string {
return process.env.GITHUB_RUN_NUMBER || process.env.GITHUB_RUN_ID || "0";
}
// ---------------------------------------------------------------------------
// Spinner
// ---------------------------------------------------------------------------
@@ -10,6 +10,7 @@ import { createJobRunLink, createCommentBody } from "./common";
import {
createForgejoJobRunLink,
createForgejoCommentBody,
getForgejoRunIndex,
} from "../../../forgejo/comment-logic";
import { detectPlatform } from "../../../platform/detector";
import {
@@ -30,7 +31,7 @@ export async function createInitialComment(
const jobRunLink =
platform === "forgejo"
? createForgejoJobRunLink(owner, repo, context.runId)
? createForgejoJobRunLink(owner, repo, getForgejoRunIndex())
: createJobRunLink(owner, repo, context.runId);
const initialBody =
platform === "forgejo"
+41
View File
@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import {
FORGEJO_SPINNER_HTML,
getForgejoRunIndex,
createForgejoJobRunLink,
createForgejoBranchLink,
createForgejoPrCompareUrl,
@@ -37,6 +38,46 @@ describe("FORGEJO_SPINNER_HTML", () => {
});
});
// ---------------------------------------------------------------------------
// getForgejoRunIndex
// ---------------------------------------------------------------------------
describe("getForgejoRunIndex", () => {
const origRunNumber = process.env.GITHUB_RUN_NUMBER;
const origRunId = process.env.GITHUB_RUN_ID;
afterEach(() => {
if (origRunNumber !== undefined) {
process.env.GITHUB_RUN_NUMBER = origRunNumber;
} else {
delete process.env.GITHUB_RUN_NUMBER;
}
if (origRunId !== undefined) {
process.env.GITHUB_RUN_ID = origRunId;
} else {
delete process.env.GITHUB_RUN_ID;
}
});
it("prefers GITHUB_RUN_NUMBER over GITHUB_RUN_ID", () => {
process.env.GITHUB_RUN_NUMBER = "661";
process.env.GITHUB_RUN_ID = "11943";
expect(getForgejoRunIndex()).toBe("661");
});
it("falls back to GITHUB_RUN_ID when GITHUB_RUN_NUMBER is not set", () => {
delete process.env.GITHUB_RUN_NUMBER;
process.env.GITHUB_RUN_ID = "11943";
expect(getForgejoRunIndex()).toBe("11943");
});
it("returns '0' when neither env var is set", () => {
delete process.env.GITHUB_RUN_NUMBER;
delete process.env.GITHUB_RUN_ID;
expect(getForgejoRunIndex()).toBe("0");
});
});
// ---------------------------------------------------------------------------
// createForgejoJobRunLink
// ---------------------------------------------------------------------------