diff --git a/src/github/utils/image-downloader.ts b/src/github/utils/image-downloader.ts
index 1e819ff..0b2c0c7 100644
--- a/src/github/utils/image-downloader.ts
+++ b/src/github/utils/image-downloader.ts
@@ -1,18 +1,24 @@
import fs from "fs/promises";
import path from "path";
import type { Octokits } from "../api/client";
-import { GITHUB_SERVER_URL } from "../api/config";
-const escapedUrl = GITHUB_SERVER_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
-const IMAGE_REGEX = new RegExp(
- `!\\[[^\\]]*\\]\\((${escapedUrl}\\/user-attachments\\/assets\\/[^)]+)\\)`,
- "g",
-);
-
-const HTML_IMG_REGEX = new RegExp(
- `
]+src=["']([^"']*${escapedUrl}\\/user-attachments\\/assets\\/[^"']+)["'][^>]*>`,
- "gi",
-);
+// Build regexes at call time, reading GITHUB_SERVER_URL from process.env
+// directly. The config.ts export freezes the value at module load time,
+// which can be wrong when the Forgejo CI runner injects its own
+// GITHUB_SERVER_URL that the shell export cannot override.
+function buildImageRegexes(): { imageRegex: RegExp; htmlImgRegex: RegExp } {
+ const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com";
+ const escapedUrl = serverUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+ const imageRegex = new RegExp(
+ `!\\[[^\\]]*\\]\\((${escapedUrl}\\/user-attachments\\/assets\\/[^)]+)\\)`,
+ "g",
+ );
+ const htmlImgRegex = new RegExp(
+ `
]+src=["']([^"']*${escapedUrl}\\/user-attachments\\/assets\\/[^"']+)["'][^>]*>`,
+ "gi",
+ );
+ return { imageRegex, htmlImgRegex };
+}
type IssueComment = {
type: "issue_comment";
@@ -63,6 +69,8 @@ export async function downloadCommentImages(
await fs.mkdir(downloadsDir, { recursive: true });
+ const { imageRegex, htmlImgRegex } = buildImageRegexes();
+
const commentsWithImages: Array<{
comment: CommentWithImages;
urls: string[];
@@ -70,11 +78,11 @@ export async function downloadCommentImages(
for (const comment of comments) {
// Extract URLs from Markdown format
- const markdownMatches = [...comment.body.matchAll(IMAGE_REGEX)];
+ const markdownMatches = [...comment.body.matchAll(imageRegex)];
const markdownUrls = markdownMatches.map((match) => match[1] as string);
// Extract URLs from HTML format
- const htmlMatches = [...comment.body.matchAll(HTML_IMG_REGEX)];
+ const htmlMatches = [...comment.body.matchAll(htmlImgRegex)];
const htmlUrls = htmlMatches.map((match) => match[1] as string);
// Combine and deduplicate URLs
diff --git a/test/image-downloader.test.ts b/test/image-downloader.test.ts
index e00b6d0..124413a 100644
--- a/test/image-downloader.test.ts
+++ b/test/image-downloader.test.ts
@@ -20,8 +20,14 @@ describe("downloadCommentImages", () => {
let fsMkdirSpy: any;
let fsWriteFileSpy: any;
let fetchSpy: any;
+ let savedServerUrl: string | undefined;
beforeEach(() => {
+ // Pin GITHUB_SERVER_URL so tests pass regardless of runner environment.
+ // The image-downloader reads process.env directly at call time.
+ savedServerUrl = process.env.GITHUB_SERVER_URL;
+ process.env.GITHUB_SERVER_URL = "https://github.com";
+
// Spy on console methods
consoleLogSpy = spyOn(console, "log").mockImplementation(() => {});
consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
@@ -36,6 +42,13 @@ describe("downloadCommentImages", () => {
});
afterEach(() => {
+ // Restore GITHUB_SERVER_URL
+ if (savedServerUrl !== undefined) {
+ process.env.GITHUB_SERVER_URL = savedServerUrl;
+ } else {
+ delete process.env.GITHUB_SERVER_URL;
+ }
+
consoleLogSpy.mockRestore();
consoleWarnSpy.mockRestore();
consoleErrorSpy.mockRestore();