diff --git a/.changeset/patch-stable-island-markers.md b/.changeset/patch-stable-island-markers.md new file mode 100644 index 0000000000..1a7c22b2d1 --- /dev/null +++ b/.changeset/patch-stable-island-markers.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Ensure update_body island markers use workflow-id so repeated runs reuse the same island instead of appending new ones. diff --git a/actions/setup/js/fuzz_update_body_harness.cjs b/actions/setup/js/fuzz_update_body_harness.cjs index 30396dfa26..19c8ea79be 100644 --- a/actions/setup/js/fuzz_update_body_harness.cjs +++ b/actions/setup/js/fuzz_update_body_harness.cjs @@ -23,10 +23,10 @@ const { updateBody } = require("./update_pr_description_helpers.cjs"); * @param {string} operation - Operation type: "append", "prepend", "replace", or "replace-island" * @param {string} workflowName - Name of the workflow * @param {string} runUrl - URL of the workflow run - * @param {number} runId - Workflow run ID + * @param {string} workflowId - Workflow ID (stable identifier across runs) * @returns {{result: string, error: string | null}} Result object */ -function testUpdateBody(currentBody, newContent, operation, workflowName, runUrl, runId) { +function testUpdateBody(currentBody, newContent, operation, workflowName, runUrl, workflowId) { try { const result = updateBody({ currentBody, @@ -34,7 +34,7 @@ function testUpdateBody(currentBody, newContent, operation, workflowName, runUrl operation, workflowName, runUrl, - runId, + workflowId, }); return { result, error: null }; } catch (err) { @@ -55,9 +55,9 @@ if (require.main === module) { process.stdin.on("end", () => { try { - // Parse input as JSON: { currentBody, newContent, operation, workflowName, runUrl, runId } - const { currentBody, newContent, operation, workflowName, runUrl, runId } = JSON.parse(input); - const result = testUpdateBody(currentBody || "", newContent || "", operation || "append", workflowName || "Test Workflow", runUrl || "https://github.com/test/actions/runs/123", runId || 123); + // Parse input as JSON: { currentBody, newContent, operation, workflowName, runUrl, workflowId } + const { currentBody, newContent, operation, workflowName, runUrl, workflowId } = JSON.parse(input); + const result = testUpdateBody(currentBody || "", newContent || "", operation || "append", workflowName || "Test Workflow", runUrl || "https://github.com/test/actions/runs/123", workflowId || "test-workflow"); process.stdout.write(JSON.stringify(result)); process.exit(0); } catch (err) { diff --git a/actions/setup/js/update_issue.cjs b/actions/setup/js/update_issue.cjs index 3c7af9d8fa..b1bcfc6b4f 100644 --- a/actions/setup/js/update_issue.cjs +++ b/actions/setup/js/update_issue.cjs @@ -52,6 +52,7 @@ async function executeIssueUpdate(github, context, issueNumber, updateData) { // Get workflow run URL for AI attribution const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; + const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; // Use helper to update body (handles all operations including replace) @@ -61,7 +62,7 @@ async function executeIssueUpdate(github, context, issueNumber, updateData) { operation, workflowName, runUrl, - runId: context.runId, + workflowId, includeFooter, // Pass footer flag to helper }); diff --git a/actions/setup/js/update_issue.test.cjs b/actions/setup/js/update_issue.test.cjs index 3eb1bbf892..27b787999f 100644 --- a/actions/setup/js/update_issue.test.cjs +++ b/actions/setup/js/update_issue.test.cjs @@ -52,6 +52,7 @@ describe("update_issue.cjs - footer support", () => { // Reset environment variables process.env.GH_AW_WORKFLOW_NAME = "Test Workflow"; + process.env.GH_AW_WORKFLOW_ID = "test-workflow"; // Reset mock implementations mockGithub.rest.issues.get.mockResolvedValue({ @@ -209,17 +210,17 @@ describe("update_issue.cjs - footer support", () => { }); const newContent = "Island content"; - const expectedBody = `Original content\n\n---\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n`; + const expectedBody = `Original content\n\n---\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n`; expect(expectedBody).toContain("Original content"); expect(expectedBody).toContain("Island content"); - expect(expectedBody).toContain(""); - expect(expectedBody).toContain(""); + expect(expectedBody).toContain(""); + expect(expectedBody).toContain(""); expect(expectedBody).toContain("> AI generated by"); }); it("should replace existing island content", async () => { - const existingBody = "Before\n\nOld island\n\nAfter"; + const existingBody = "Before\n\nOld island\n\nAfter"; mockGithub.rest.issues.get.mockResolvedValueOnce({ data: { number: 100, @@ -230,7 +231,7 @@ describe("update_issue.cjs - footer support", () => { }); const newContent = "New island"; - const expectedBody = `Before\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n\nAfter`; + const expectedBody = `Before\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n\nAfter`; expect(expectedBody).toContain("Before"); expect(expectedBody).toContain("After"); @@ -456,17 +457,17 @@ describe("update_issue.cjs - footer support", () => { }); const newContent = "New island"; - // Should append because island with run ID 12345 doesn't exist - const expectedBody = `${existingBody}\n\n---\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n`; + // Should append because island with workflow test-workflow doesn't exist + const expectedBody = `${existingBody}\n\n---\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n`; expect(expectedBody).toContain("Other island"); expect(expectedBody).toContain("New island"); expect(expectedBody).toContain(""); - expect(expectedBody).toContain(""); + expect(expectedBody).toContain(""); }); it("should preserve content outside island when replacing", async () => { - const existingBody = "# Title\n\n\nOld\n\n\n## Footer"; + const existingBody = "# Title\n\n\nOld\n\n\n## Footer"; mockGithub.rest.issues.get.mockResolvedValueOnce({ data: { number: 100, @@ -477,7 +478,7 @@ describe("update_issue.cjs - footer support", () => { }); const newContent = "Updated content"; - const expectedBody = `# Title\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n\n\n## Footer`; + const expectedBody = `# Title\n\n\n${newContent}\n\n> AI generated by [Test Workflow](https://github.com/testowner/testrepo/actions/runs/12345)\n\n\n## Footer`; expect(expectedBody).toContain("# Title"); expect(expectedBody).toContain("## Footer"); diff --git a/actions/setup/js/update_pr_description_helpers.cjs b/actions/setup/js/update_pr_description_helpers.cjs index c4d993b13c..a666548229 100644 --- a/actions/setup/js/update_pr_description_helpers.cjs +++ b/actions/setup/js/update_pr_description_helpers.cjs @@ -22,31 +22,31 @@ function buildAIFooter(workflowName, runUrl) { /** * Build the island start marker for replace-island mode - * @param {number} runId - Workflow run ID + * @param {string} workflowId - Workflow ID (stable identifier across runs) * @returns {string} Island start marker */ -function buildIslandStartMarker(runId) { - return ``; +function buildIslandStartMarker(workflowId) { + return ``; } /** * Build the island end marker for replace-island mode - * @param {number} runId - Workflow run ID + * @param {string} workflowId - Workflow ID (stable identifier across runs) * @returns {string} Island end marker */ -function buildIslandEndMarker(runId) { - return ``; +function buildIslandEndMarker(workflowId) { + return ``; } /** * Find and extract island content from body * @param {string} body - The body content to search - * @param {number} runId - Workflow run ID + * @param {string} workflowId - Workflow ID (stable identifier across runs) * @returns {{found: boolean, startIndex: number, endIndex: number}} Island location info */ -function findIsland(body, runId) { - const startMarker = buildIslandStartMarker(runId); - const endMarker = buildIslandEndMarker(runId); +function findIsland(body, workflowId) { + const startMarker = buildIslandStartMarker(workflowId); + const endMarker = buildIslandEndMarker(workflowId); const startIndex = body.indexOf(startMarker); if (startIndex === -1) { @@ -70,12 +70,12 @@ function findIsland(body, runId) { * @param {string} params.operation - Operation type: "append", "prepend", "replace", or "replace-island" * @param {string} params.workflowName - Name of the workflow * @param {string} params.runUrl - URL of the workflow run - * @param {number} params.runId - Workflow run ID + * @param {string} params.workflowId - Workflow ID (stable identifier across runs) * @param {boolean} [params.includeFooter=true] - Whether to include AI-generated footer (default: true) * @returns {string} Updated body content */ function updateBody(params) { - const { currentBody, newContent, operation, workflowName, runUrl, runId, includeFooter = true } = params; + const { currentBody, newContent, operation, workflowName, runUrl, workflowId, includeFooter = true } = params; const aiFooter = includeFooter ? buildAIFooter(workflowName, runUrl) : ""; if (operation === "replace") { @@ -85,14 +85,14 @@ function updateBody(params) { } if (operation === "replace-island") { - // Try to find existing island for this run ID - const island = findIsland(currentBody, runId); + // Try to find existing island for this workflow ID + const island = findIsland(currentBody, workflowId); if (island.found) { // Replace the island content - core.info(`Operation: replace-island (updating existing island for run ${runId})`); - const startMarker = buildIslandStartMarker(runId); - const endMarker = buildIslandEndMarker(runId); + core.info(`Operation: replace-island (updating existing island for workflow ${workflowId})`); + const startMarker = buildIslandStartMarker(workflowId); + const endMarker = buildIslandEndMarker(workflowId); const islandContent = `${startMarker}\n${newContent}${aiFooter}\n${endMarker}`; const before = currentBody.substring(0, island.startIndex); @@ -100,9 +100,9 @@ function updateBody(params) { return before + islandContent + after; } else { // Island not found, fall back to append mode - core.info(`Operation: replace-island (island not found for run ${runId}, falling back to append)`); - const startMarker = buildIslandStartMarker(runId); - const endMarker = buildIslandEndMarker(runId); + core.info(`Operation: replace-island (island not found for workflow ${workflowId}, falling back to append)`); + const startMarker = buildIslandStartMarker(workflowId); + const endMarker = buildIslandEndMarker(workflowId); const islandContent = `${startMarker}\n${newContent}${aiFooter}\n${endMarker}`; const appendSection = `\n\n---\n\n${islandContent}`; return currentBody + appendSection; diff --git a/actions/setup/js/update_pr_description_helpers.test.cjs b/actions/setup/js/update_pr_description_helpers.test.cjs index 61888854ed..20c41561f2 100644 --- a/actions/setup/js/update_pr_description_helpers.test.cjs +++ b/actions/setup/js/update_pr_description_helpers.test.cjs @@ -34,64 +34,64 @@ describe("update_pr_description_helpers.cjs", () => { }); describe("buildIslandStartMarker", () => { - it("should build island start marker with run ID", () => { - const marker = buildIslandStartMarker(12345); - expect(marker).toBe(""); + it("should build island start marker with workflow ID", () => { + const marker = buildIslandStartMarker("test-workflow"); + expect(marker).toBe(""); }); - it("should handle different run IDs", () => { - expect(buildIslandStartMarker(1)).toBe(""); - expect(buildIslandStartMarker(999999)).toBe(""); + it("should handle different workflow IDs", () => { + expect(buildIslandStartMarker("workflow-1")).toBe(""); + expect(buildIslandStartMarker("my-awesome-workflow")).toBe(""); }); }); describe("buildIslandEndMarker", () => { - it("should build island end marker with run ID", () => { - const marker = buildIslandEndMarker(12345); - expect(marker).toBe(""); + it("should build island end marker with workflow ID", () => { + const marker = buildIslandEndMarker("test-workflow"); + expect(marker).toBe(""); }); - it("should handle different run IDs", () => { - expect(buildIslandEndMarker(1)).toBe(""); - expect(buildIslandEndMarker(999999)).toBe(""); + it("should handle different workflow IDs", () => { + expect(buildIslandEndMarker("workflow-1")).toBe(""); + expect(buildIslandEndMarker("my-awesome-workflow")).toBe(""); }); }); describe("findIsland", () => { it("should find island when both markers are present", () => { - const body = "Before\n\nIsland content\n\nAfter"; - const result = findIsland(body, 123); + const body = "Before\n\nIsland content\n\nAfter"; + const result = findIsland(body, "test-workflow"); expect(result.found).toBe(true); expect(result.startIndex).toBeGreaterThanOrEqual(0); expect(result.endIndex).toBeGreaterThan(result.startIndex); }); it("should not find island when start marker is missing", () => { - const body = "Before\nIsland content\n\nAfter"; - const result = findIsland(body, 123); + const body = "Before\nIsland content\n\nAfter"; + const result = findIsland(body, "test-workflow"); expect(result.found).toBe(false); expect(result.startIndex).toBe(-1); expect(result.endIndex).toBe(-1); }); it("should not find island when end marker is missing", () => { - const body = "Before\n\nIsland content\nAfter"; - const result = findIsland(body, 123); + const body = "Before\n\nIsland content\nAfter"; + const result = findIsland(body, "test-workflow"); expect(result.found).toBe(false); expect(result.startIndex).toBe(-1); expect(result.endIndex).toBe(-1); }); - it("should not find island when run ID does not match", () => { - const body = "Before\n\nIsland content\n\nAfter"; - const result = findIsland(body, 456); + it("should not find island when workflow ID does not match", () => { + const body = "Before\n\nIsland content\n\nAfter"; + const result = findIsland(body, "workflow-b"); expect(result.found).toBe(false); }); - it("should handle multiple islands with different run IDs", () => { - const body = "\nIsland 1\n\n\nIsland 2\n"; - const result1 = findIsland(body, 100); - const result2 = findIsland(body, 200); + it("should handle multiple islands with different workflow IDs", () => { + const body = "\nIsland 1\n\n\nIsland 2\n"; + const result1 = findIsland(body, "workflow-1"); + const result2 = findIsland(body, "workflow-2"); expect(result1.found).toBe(true); expect(result2.found).toBe(true); expect(result1.startIndex).toBeLessThan(result2.startIndex); @@ -106,7 +106,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "replace", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("New content"); expect(result).not.toContain("Old content"); @@ -125,7 +125,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("---"); expect(result).toContain("New content"); @@ -142,7 +142,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Original content"); expect(result).toContain("New content"); @@ -156,7 +156,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("# Title"); expect(result).toContain("**Bold**"); @@ -172,7 +172,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "prepend", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("---"); expect(result).toContain("New content"); @@ -189,7 +189,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "prepend", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Original content"); expect(result).toContain("New content"); @@ -205,12 +205,12 @@ describe("update_pr_description_helpers.cjs", () => { operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Original content"); expect(result).toContain("Island content"); - expect(result).toContain(""); - expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); // Check for footer elements (uses messages system) expect(result).toContain("Test"); expect(result).toContain("https://github.com/test/actions/runs/123"); @@ -218,33 +218,33 @@ describe("update_pr_description_helpers.cjs", () => { }); it("should replace existing island content", () => { - const currentBody = "Before\n\nOld island\n\nAfter"; + const currentBody = "Before\n\nOld island\n\nAfter"; const result = updateBody({ currentBody, newContent: "New island", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Before"); expect(result).toContain("After"); expect(result).toContain("New island"); expect(result).not.toContain("Old island"); - expect(result).toContain(""); - expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("updating existing island")); }); it("should preserve content outside island when replacing", () => { - const currentBody = "# Title\n\nSome intro\n\n\nOld\n\n\n## Footer\n\nMore content"; + const currentBody = "# Title\n\nSome intro\n\n\nOld\n\n\n## Footer\n\nMore content"; const result = updateBody({ currentBody, newContent: "Updated content", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("# Title"); expect(result).toContain("Some intro"); @@ -254,33 +254,33 @@ describe("update_pr_description_helpers.cjs", () => { expect(result).not.toContain("Old"); }); - it("should not replace island with different run ID", () => { - const currentBody = "Before\n\nOther island\n\nAfter"; + it("should not replace island with different workflow ID", () => { + const currentBody = "Before\n\nOther island\n\nAfter"; const result = updateBody({ currentBody, newContent: "New island", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); - // Should append because island 123 doesn't exist + // Should append because island test-workflow doesn't exist expect(result).toContain("Other island"); expect(result).toContain("New island"); - expect(result).toContain(""); - expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("falling back to append")); }); - it("should handle multiple islands with same run ID (replace first)", () => { - const currentBody = "\nFirst\n\n\nSecond\n"; + it("should handle multiple islands with same workflow ID (replace first)", () => { + const currentBody = "\nFirst\n\n\nSecond\n"; const result = updateBody({ currentBody, newContent: "Replaced", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Replaced"); // First island should be replaced @@ -288,14 +288,14 @@ describe("update_pr_description_helpers.cjs", () => { }); it("should handle empty island content", () => { - const currentBody = "Before\n\n\n\nAfter"; + const currentBody = "Before\n\n\n\nAfter"; const result = updateBody({ currentBody, newContent: "New content", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("New content"); expect(result).toContain("Before"); @@ -303,14 +303,14 @@ describe("update_pr_description_helpers.cjs", () => { }); it("should handle special characters in island content", () => { - const currentBody = "\nOld\n"; + const currentBody = "\nOld\n"; const result = updateBody({ currentBody, newContent: "Content with **markdown**, `code`, [links](http://example.com)", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("**markdown**"); expect(result).toContain("`code`"); @@ -318,14 +318,14 @@ describe("update_pr_description_helpers.cjs", () => { }); it("should handle newlines and whitespace correctly", () => { - const currentBody = "\n \n\nOld\n\n \n"; + const currentBody = "\n \n\nOld\n\n \n"; const result = updateBody({ currentBody, newContent: "New\n\nMultiline\n\nContent", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("New\n\nMultiline\n\nContent"); }); @@ -339,7 +339,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Original"); // Check for footer elements @@ -353,7 +353,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("New"); }); @@ -365,7 +365,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("你好"); expect(result).toContain("世界 🚀"); @@ -379,7 +379,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain(longContent); expect(result.length).toBeGreaterThan(10000); @@ -392,7 +392,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "unknown", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", }); expect(result).toContain("Original"); expect(result).toContain("New"); @@ -409,7 +409,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", includeFooter: false, }); expect(result).toContain("Original"); @@ -425,7 +425,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", // includeFooter not specified, should default to true }); expect(result).toContain("Original"); @@ -440,7 +440,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "append", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", includeFooter: true, }); expect(result).toContain("Original"); @@ -455,7 +455,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "replace", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", includeFooter: false, }); expect(result).toBe("Replacement"); @@ -469,7 +469,7 @@ describe("update_pr_description_helpers.cjs", () => { operation: "prepend", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", includeFooter: false, }); expect(result).toContain("Prepended"); @@ -478,22 +478,22 @@ describe("update_pr_description_helpers.cjs", () => { }); it("should omit footer in replace-island operation when includeFooter is false", () => { - const currentBody = "Before\n\nOld island\n\nAfter"; + const currentBody = "Before\n\nOld island\n\nAfter"; const result = updateBody({ currentBody, newContent: "New island", operation: "replace-island", workflowName: "Test", runUrl: "https://github.com/test/actions/runs/123", - runId: 123, + workflowId: "test-workflow", includeFooter: false, }); expect(result).toContain("Before"); expect(result).toContain("New island"); expect(result).toContain("After"); expect(result).not.toContain("Generated by"); - expect(result).toContain(""); - expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); }); }); }); diff --git a/actions/setup/js/update_pull_request.cjs b/actions/setup/js/update_pull_request.cjs index 04f825c421..3cca5ad45e 100644 --- a/actions/setup/js/update_pull_request.cjs +++ b/actions/setup/js/update_pull_request.cjs @@ -41,6 +41,7 @@ async function executePRUpdate(github, context, prNumber, updateData) { // Get workflow run URL for AI attribution const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; + const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; // Use helper to update body (handles all operations including replace) @@ -50,7 +51,7 @@ async function executePRUpdate(github, context, prNumber, updateData) { operation, workflowName, runUrl, - runId: context.runId, + workflowId, }); core.info(`Will update body (length: ${apiData.body.length})`); diff --git a/actions/setup/js/update_release.cjs b/actions/setup/js/update_release.cjs index 08611d3116..667974151a 100644 --- a/actions/setup/js/update_release.cjs +++ b/actions/setup/js/update_release.cjs @@ -83,6 +83,7 @@ async function main(config = {}) { // Get workflow run URL for AI attribution const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; // Use shared helper to update body based on operation const newBody = updateBody({ @@ -91,7 +92,7 @@ async function main(config = {}) { operation: message.operation || "append", workflowName, runUrl, - runId: context.runId, + workflowId, includeFooter, // Pass footer flag to helper });