From 36bfc9d5d033be6b209fb932b59a4eb8921e818d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:31:53 +0000 Subject: [PATCH 1/3] Initial plan From d41fac897700c171f593b93578d877d9d825dee1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:48:22 +0000 Subject: [PATCH 2/3] Add append-only marker to prevent hiding of append-only comments - When append-only-comments is enabled, add_comment now includes a marker - This marker prevents the comment from being hidden by future workflow runs - Updated filtering logic to exclude append-only comments from hiding - Added comprehensive tests to verify the behavior Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/add_comment.cjs | 11 ++- actions/setup/js/add_comment.test.cjs | 109 ++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/add_comment.cjs b/actions/setup/js/add_comment.cjs index 1ed4a3c1945..b5cf2506a68 100644 --- a/actions/setup/js/add_comment.cjs +++ b/actions/setup/js/add_comment.cjs @@ -66,9 +66,9 @@ async function findCommentsWithTrackerId(github, owner, repo, issueNumber, workf break; } - // Filter comments that contain the workflow-id and are NOT reaction comments + // Filter comments that contain the workflow-id and are NOT reaction or append-only comments const filteredComments = data - .filter(comment => comment.body?.includes(``) && !comment.body.includes(``)) + .filter(comment => comment.body?.includes(``) && !comment.body.includes(``) && !comment.body.includes(``)) .map(({ id, node_id, body }) => ({ id, node_id, body })); comments.push(...filteredComments); @@ -123,7 +123,7 @@ async function findDiscussionCommentsWithTrackerId(github, owner, repo, discussi } const filteredComments = result.repository.discussion.comments.nodes - .filter(comment => comment.body?.includes(``) && !comment.body.includes(``)) + .filter(comment => comment.body?.includes(``) && !comment.body.includes(``) && !comment.body.includes(``)) .map(({ id, body }) => ({ id, body })); comments.push(...filteredComments); @@ -414,6 +414,11 @@ async function main(config = {}) { processedBody += "\n\n" + trackerIDComment; } + // Add append-only marker if enabled to prevent hiding by future runs + if (appendOnlyComments) { + processedBody += "\n\n"; + } + const workflowName = process.env.GH_AW_WORKFLOW_NAME || "Workflow"; const runId = context.runId; const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; diff --git a/actions/setup/js/add_comment.test.cjs b/actions/setup/js/add_comment.test.cjs index f5a9b7beb67..6a17d300d07 100644 --- a/actions/setup/js/add_comment.test.cjs +++ b/actions/setup/js/add_comment.test.cjs @@ -527,5 +527,114 @@ describe("add_comment", () => { // Clean up delete process.env.GITHUB_WORKFLOW; }); + + it("should include append-only marker in comment body when append-only-comments is enabled", async () => { + const addCommentScript = fs.readFileSync(path.join(__dirname, "add_comment.cjs"), "utf8"); + + // Set up environment variable for append-only-comments + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ + appendOnlyComments: true, + }); + process.env.GITHUB_WORKFLOW = "test-workflow"; + + let capturedComment = null; + mockGithub.rest.issues.createComment = async params => { + capturedComment = params; + return { + data: { + id: 12345, + html_url: `https://github.com/owner/repo/issues/${params.issue_number}#issuecomment-12345`, + }, + }; + }; + + const handler = await eval(`(async () => { ${addCommentScript}; return await main({}); })()`); + + const message = { + type: "add_comment", + body: "Append-only comment", + }; + + const result = await handler(message, {}); + + expect(result.success).toBe(true); + expect(capturedComment).toBeTruthy(); + expect(capturedComment.body).toContain(""); + + // Clean up + delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES; + delete process.env.GITHUB_WORKFLOW; + }); + + it("should not hide append-only comments from previous runs", async () => { + const addCommentScript = fs.readFileSync(path.join(__dirname, "add_comment.cjs"), "utf8"); + + // Set up environment WITHOUT append-only-comments (new run) + delete process.env.GH_AW_SAFE_OUTPUT_MESSAGES; + process.env.GITHUB_WORKFLOW = "test-workflow"; + + let hideCommentsWasCalled = false; + let hiddenCommentIds = []; + + // Simulate finding an old append-only comment and a regular comment + mockGithub.rest.issues.listComments = async () => { + return { + data: [ + { + id: 888, + node_id: "IC_kwDOTest888", + body: "Old append-only comment ", + }, + { + id: 999, + node_id: "IC_kwDOTest999", + body: "Old regular comment ", + }, + ], + }; + }; + + mockGithub.graphql = async (query, variables) => { + if (query.includes("minimizeComment")) { + hideCommentsWasCalled = true; + hiddenCommentIds.push(variables.nodeId); + } + return { + minimizeComment: { + minimizedComment: { + isMinimized: true, + }, + }, + }; + }; + + mockGithub.rest.issues.createComment = async params => { + return { + data: { + id: 12345, + html_url: `https://github.com/owner/repo/issues/${params.issue_number}#issuecomment-12345`, + }, + }; + }; + + // Execute with hide-older-comments enabled (but not append-only) + const handler = await eval(`(async () => { ${addCommentScript}; return await main({ hide_older_comments: true }); })()`); + + const message = { + type: "add_comment", + body: "New comment", + }; + + const result = await handler(message, {}); + + expect(result.success).toBe(true); + expect(hideCommentsWasCalled).toBe(true); + // Should only hide the regular comment, not the append-only comment + expect(hiddenCommentIds).toEqual(["IC_kwDOTest999"]); + expect(hiddenCommentIds).not.toContain("IC_kwDOTest888"); + + // Clean up + delete process.env.GITHUB_WORKFLOW; + }); }); }); From c814b1864f664d1e2ead18dbd273e5a352d32e09 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:56:18 +0000 Subject: [PATCH 3/3] Refactor: extract shouldHideComment helper function - Extracted comment filtering logic into shouldHideComment helper - Reduces code duplication between issue and discussion comment handling - Improves readability and maintainability - All tests still passing Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/add_comment.cjs | 42 ++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/actions/setup/js/add_comment.cjs b/actions/setup/js/add_comment.cjs index b5cf2506a68..8611d6ea52f 100644 --- a/actions/setup/js/add_comment.cjs +++ b/actions/setup/js/add_comment.cjs @@ -38,6 +38,38 @@ async function minimizeComment(github, nodeId, reason = "outdated") { }; } +/** + * Check if a comment should be hidden by the hideOlderComments function + * @param {string} commentBody - The comment body text + * @param {string} workflowId - The workflow ID to match + * @returns {boolean} true if the comment should be hidden, false otherwise + */ +function shouldHideComment(commentBody, workflowId) { + if (!commentBody) { + return false; + } + + // Comment must have the workflow-id marker + const hasWorkflowId = commentBody.includes(``); + if (!hasWorkflowId) { + return false; + } + + // Exclude reaction comments (activation comments) + const isReactionComment = commentBody.includes(``); + if (isReactionComment) { + return false; + } + + // Exclude append-only comments (should persist across runs) + const isAppendOnlyComment = commentBody.includes(``); + if (isAppendOnlyComment) { + return false; + } + + return true; +} + /** * Find comments on an issue/PR with a specific tracker-id * @param {any} github - GitHub REST API instance @@ -66,10 +98,8 @@ async function findCommentsWithTrackerId(github, owner, repo, issueNumber, workf break; } - // Filter comments that contain the workflow-id and are NOT reaction or append-only comments - const filteredComments = data - .filter(comment => comment.body?.includes(``) && !comment.body.includes(``) && !comment.body.includes(``)) - .map(({ id, node_id, body }) => ({ id, node_id, body })); + // Filter comments that should be hidden + const filteredComments = data.filter(comment => shouldHideComment(comment.body, workflowId)).map(({ id, node_id, body }) => ({ id, node_id, body })); comments.push(...filteredComments); @@ -122,9 +152,7 @@ async function findDiscussionCommentsWithTrackerId(github, owner, repo, discussi break; } - const filteredComments = result.repository.discussion.comments.nodes - .filter(comment => comment.body?.includes(``) && !comment.body.includes(``) && !comment.body.includes(``)) - .map(({ id, body }) => ({ id, body })); + const filteredComments = result.repository.discussion.comments.nodes.filter(comment => shouldHideComment(comment.body, workflowId)).map(({ id, body }) => ({ id, body })); comments.push(...filteredComments);