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:
1 parent
6ebfb4914f
commit
23f15aecb9
6 files changed
+109
-10
No files matched your search
@@ -13,6 +13,11 @@ concurrency:
|
|||||||
group: ci-${{ github.ref }}
|
group: ci-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
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:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
@@ -25,9 +30,16 @@ jobs:
|
|||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
run: |
|
run: |
|
||||||
if command -v bun &> /dev/null; then
|
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
|
||||||
|
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
|
else
|
||||||
curl -fsSL https://bun.sh/install | bash
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -56,9 +68,16 @@ jobs:
|
|||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
run: |
|
run: |
|
||||||
if command -v bun &> /dev/null; then
|
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
|
||||||
|
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
|
else
|
||||||
curl -fsSL https://bun.sh/install | bash
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -79,9 +98,16 @@ jobs:
|
|||||||
- name: Install Bun
|
- name: Install Bun
|
||||||
run: |
|
run: |
|
||||||
if command -v bun &> /dev/null; then
|
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
|
||||||
|
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
|
else
|
||||||
curl -fsSL https://bun.sh/install | bash
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import {
|
|||||||
import type { ParsedGitHubContext } from "../github/context";
|
import type { ParsedGitHubContext } from "../github/context";
|
||||||
import type { CommonFields, PreparedContext, EventData } from "./types";
|
import type { CommonFields, PreparedContext, EventData } from "./types";
|
||||||
import { GITHUB_SERVER_URL } from "../github/api/config";
|
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";
|
import { extractUserRequest } from "../utils/extract-user-request";
|
||||||
export type { CommonFields, PreparedContext } from "./types";
|
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";
|
: "No description provided";
|
||||||
|
|
||||||
const entityType = eventData.isPR ? "pull request" : "issue";
|
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.
|
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 { eventData } = context;
|
||||||
|
|
||||||
const { eventType, triggerContext } = getEventTypeAndContext(context);
|
const { eventType, triggerContext } = getEventTypeAndContext(context);
|
||||||
|
const runIdentifier =
|
||||||
|
detectPlatform() === "forgejo"
|
||||||
|
? getForgejoRunIndex()
|
||||||
|
: process.env.GITHUB_RUN_ID;
|
||||||
|
|
||||||
const formattedContext = formatContext(contextData, eventData.isPR);
|
const formattedContext = formatContext(contextData, eventData.isPR);
|
||||||
const formattedComments = formatComments(comments, imageUrlMap);
|
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.
|
- 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.
|
- 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 (#).
|
- 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:
|
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.
|
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.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
updateForgejoCommentBody,
|
updateForgejoCommentBody,
|
||||||
createForgejoPrCompareUrl,
|
createForgejoPrCompareUrl,
|
||||||
|
getForgejoRunIndex,
|
||||||
} from "../forgejo/comment-logic";
|
} from "../forgejo/comment-logic";
|
||||||
import { detectPlatform } from "../platform/detector";
|
import { detectPlatform } from "../platform/detector";
|
||||||
import {
|
import {
|
||||||
@@ -54,7 +55,9 @@ export async function updateCommentLink(
|
|||||||
const platform = detectPlatform();
|
const platform = detectPlatform();
|
||||||
|
|
||||||
const serverUrl = GITHUB_SERVER_URL;
|
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 comment;
|
||||||
let isPRReviewComment = false;
|
let isPRReviewComment = false;
|
||||||
|
|||||||
@@ -34,6 +34,24 @@ function getServerUrl(): string {
|
|||||||
return process.env.GITHUB_SERVER_URL || "https://github.com";
|
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
|
// Spinner
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { createJobRunLink, createCommentBody } from "./common";
|
|||||||
import {
|
import {
|
||||||
createForgejoJobRunLink,
|
createForgejoJobRunLink,
|
||||||
createForgejoCommentBody,
|
createForgejoCommentBody,
|
||||||
|
getForgejoRunIndex,
|
||||||
} from "../../../forgejo/comment-logic";
|
} from "../../../forgejo/comment-logic";
|
||||||
import { detectPlatform } from "../../../platform/detector";
|
import { detectPlatform } from "../../../platform/detector";
|
||||||
import {
|
import {
|
||||||
@@ -30,7 +31,7 @@ export async function createInitialComment(
|
|||||||
|
|
||||||
const jobRunLink =
|
const jobRunLink =
|
||||||
platform === "forgejo"
|
platform === "forgejo"
|
||||||
? createForgejoJobRunLink(owner, repo, context.runId)
|
? createForgejoJobRunLink(owner, repo, getForgejoRunIndex())
|
||||||
: createJobRunLink(owner, repo, context.runId);
|
: createJobRunLink(owner, repo, context.runId);
|
||||||
const initialBody =
|
const initialBody =
|
||||||
platform === "forgejo"
|
platform === "forgejo"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
||||||
import {
|
import {
|
||||||
FORGEJO_SPINNER_HTML,
|
FORGEJO_SPINNER_HTML,
|
||||||
|
getForgejoRunIndex,
|
||||||
createForgejoJobRunLink,
|
createForgejoJobRunLink,
|
||||||
createForgejoBranchLink,
|
createForgejoBranchLink,
|
||||||
createForgejoPrCompareUrl,
|
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
|
// createForgejoJobRunLink
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user