-
Notifications
You must be signed in to change notification settings - Fork 295
Add history link (◷) to add_comment, update_issue, and update_pull_request footers #19344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
852315a
225bb61
e7f0b40
b82769a
ccad1df
d01c140
405dd9f
3d2ebde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ const { logStagedPreviewInfo } = require("./staged_preview.cjs"); | |
| const { ERR_NOT_FOUND } = require("./error_codes.cjs"); | ||
| const { isPayloadUserBot } = require("./resolve_mentions.cjs"); | ||
| const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); | ||
| const { generateHistoryUrl } = require("./generate_history_link.cjs"); | ||
|
|
||
| /** @type {string} Safe output type handled by this module */ | ||
| const HANDLER_TYPE = "add_comment"; | ||
|
|
@@ -335,6 +336,7 @@ async function main(config = {}) { | |
|
|
||
| // Get workflow ID for hiding older comments | ||
| const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; | ||
| const callerWorkflowId = process.env.GH_AW_CALLER_WORKFLOW_ID || ""; | ||
|
|
||
| /** | ||
| * Message handler function | ||
|
|
@@ -525,9 +527,22 @@ async function main(config = {}) { | |
| const triggeringPRNumber = context.payload.pull_request?.number; | ||
| const triggeringDiscussionNumber = context.payload.discussion?.number; | ||
|
|
||
| // Generate history URL: use in:comments for issue/PR comments; skip for discussion comments | ||
| // (GitHub search does not support in:comments for discussions) | ||
| const historyUrl = !isDiscussion | ||
| ? generateHistoryUrl({ | ||
| owner: repoParts.owner, | ||
| repo: repoParts.repo, | ||
| itemType: "comment", | ||
| workflowCallId: callerWorkflowId, | ||
| workflowId, | ||
| serverUrl: context.serverUrl, | ||
github-actions[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| }) || undefined | ||
| : undefined; | ||
|
|
||
| if (includeFooter) { | ||
| // When footer is enabled, add full footer with attribution and XML markers | ||
| processedBody += generateFooterWithMessages(workflowName, runUrl, workflowSource, workflowSourceURL, triggeringIssueNumber, triggeringPRNumber, triggeringDiscussionNumber).trimEnd(); | ||
| processedBody += generateFooterWithMessages(workflowName, runUrl, workflowSource, workflowSourceURL, triggeringIssueNumber, triggeringPRNumber, triggeringDiscussionNumber, historyUrl).trimEnd(); | ||
| } else { | ||
| // When footer is disabled, only add XML marker for searchability (no visible attribution text) | ||
| processedBody += "\n\n" + generateXMLMarker(workflowName, runUrl); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,14 +11,14 @@ | |
| */ | ||
|
|
||
| /** | ||
| * @typedef {"issue" | "pull_request" | "discussion"} ItemType | ||
| * @typedef {"issue" | "pull_request" | "discussion" | "comment"} ItemType | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef {Object} HistoryLinkParams | ||
| * @property {string} owner - Repository owner | ||
| * @property {string} repo - Repository name | ||
| * @property {ItemType} itemType - Type of GitHub item: "issue", "pull_request", or "discussion" | ||
| * @property {ItemType} itemType - Type of GitHub item: "issue", "pull_request", "discussion", or "comment" | ||
| * @property {string} [workflowCallId] - Caller workflow ID (e.g. "owner/repo/WorkflowName"). Takes precedence over workflowId. | ||
| * @property {string} [workflowId] - Workflow identifier. Used when workflowCallId is not available. | ||
| * @property {string} [serverUrl] - GitHub server URL for enterprise deployments (e.g. "https://github.example.com"). Defaults to "https://github.com". | ||
|
|
@@ -51,32 +51,20 @@ function generateHistoryUrl({ owner, repo, itemType, workflowCallId, workflowId, | |
| // Build the search query parts | ||
| const queryParts = [`repo:${owner}/${repo}`]; | ||
|
|
||
| // Add item type qualifier (issues and PRs use is: qualifiers; discussions use type= param only) | ||
| // Add item type qualifier (issues and PRs use is: qualifiers; discussions and comments do not) | ||
| if (itemType === "issue") { | ||
| queryParts.push("is:issue"); | ||
| } else if (itemType === "pull_request") { | ||
| queryParts.push("is:pr"); | ||
| } | ||
|
|
||
| // Search for the XML marker in the body | ||
| // Search for the XML marker in the appropriate field | ||
| // Comments use in:comments (searches comment bodies); all others use in:body | ||
| queryParts.push(`"${markerId}"`); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good addition of the |
||
| queryParts.push("in:body"); | ||
|
|
||
| // Determine the search result type parameter | ||
| let typeParam; | ||
| if (itemType === "issue") { | ||
| typeParam = "issues"; | ||
| } else if (itemType === "pull_request") { | ||
| typeParam = "pullrequests"; | ||
| } else if (itemType === "discussion") { | ||
| typeParam = "discussions"; | ||
| } | ||
| queryParts.push(itemType === "comment" ? "in:comments" : "in:body"); | ||
|
|
||
| const url = new URL(`${server}/search`); | ||
| url.searchParams.set("q", queryParts.join(" ")); | ||
| if (typeParam) { | ||
| url.searchParams.set("type", typeParam); | ||
| } | ||
|
|
||
| return url.toString(); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,7 +45,7 @@ describe("generate_history_link.cjs", () => { | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| expect(url).toContain("is%3Aissue"); | ||||||||||||||||||||||||||||||||||
| expect(url).toContain("type=issues"); | ||||||||||||||||||||||||||||||||||
| expect(url).not.toContain("type="); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| it("should include is:pr qualifier for pull_request type", () => { | ||||||||||||||||||||||||||||||||||
|
|
@@ -58,7 +58,7 @@ describe("generate_history_link.cjs", () => { | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| expect(url).toContain("is%3Apr"); | ||||||||||||||||||||||||||||||||||
| expect(url).toContain("type=pullrequests"); | ||||||||||||||||||||||||||||||||||
| expect(url).not.toContain("type="); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| it("should NOT include is: qualifier for discussion type", () => { | ||||||||||||||||||||||||||||||||||
|
|
@@ -71,7 +71,7 @@ describe("generate_history_link.cjs", () => { | |||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| expect(url).not.toContain("is%3A"); | ||||||||||||||||||||||||||||||||||
| expect(url).toContain("type=discussions"); | ||||||||||||||||||||||||||||||||||
| expect(url).not.toContain("type="); | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| }); | |
| }); | |
| it("should filter by comments without is: qualifiers for comment type", () => { | |
| const url = generateHistoryUrl({ | |
| owner: "testowner", | |
| repo: "testrepo", | |
| itemType: "comment", | |
| workflowId: "my-workflow", | |
| serverUrl: "https://github.com", | |
| }); | |
| expect(url).toContain("in%3Acomments"); | |
| expect(url).not.toContain("is%3A"); | |
| expect(url).not.toContain("type="); | |
| }); |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ const { tryEnforceArrayLimit } = require("./limit_enforcement_helpers.cjs"); | |||
| const { ERR_VALIDATION } = require("./error_codes.cjs"); | ||||
| const { parseBoolTemplatable } = require("./templatable.cjs"); | ||||
| const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); | ||||
| const { generateHistoryUrl } = require("./generate_history_link.cjs"); | ||||
|
|
||||
| /** | ||||
| * Maximum limits for issue update parameters to prevent resource exhaustion. | ||||
|
|
@@ -80,9 +81,20 @@ async function executeIssueUpdate(github, context, issueNumber, updateData) { | |||
| // context may be effectiveContext with repo overridden to a cross-repo target. | ||||
| const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; | ||||
| const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; | ||||
| const callerWorkflowId = process.env.GH_AW_CALLER_WORKFLOW_ID || ""; | ||||
| const workflowRepo = _workflowRepo || context.repo; | ||||
| const runUrl = buildWorkflowRunUrl(context, workflowRepo); | ||||
|
|
||||
| const historyUrl = | ||||
| generateHistoryUrl({ | ||||
| owner: context.repo.owner, | ||||
| repo: context.repo.repo, | ||||
| itemType: "issue", | ||||
| workflowCallId: callerWorkflowId, | ||||
|
||||
| workflowCallId: callerWorkflowId, |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -14,6 +14,7 @@ const { createUpdateHandlerFactory, createStandardResolveNumber, createStandardF | |||
| const { sanitizeTitle } = require("./sanitize_title.cjs"); | ||||
| const { parseBoolTemplatable } = require("./templatable.cjs"); | ||||
| const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs"); | ||||
| const { generateHistoryUrl } = require("./generate_history_link.cjs"); | ||||
|
|
||||
| /** | ||||
| * Execute the pull request update API call | ||||
|
|
@@ -47,9 +48,20 @@ async function executePRUpdate(github, context, prNumber, updateData) { | |||
| // context may be effectiveContext with repo overridden to a cross-repo target. | ||||
| const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; | ||||
| const workflowId = process.env.GH_AW_WORKFLOW_ID || ""; | ||||
| const callerWorkflowId = process.env.GH_AW_CALLER_WORKFLOW_ID || ""; | ||||
| const workflowRepo = _workflowRepo || context.repo; | ||||
| const runUrl = buildWorkflowRunUrl(context, workflowRepo); | ||||
|
|
||||
| const historyUrl = | ||||
| generateHistoryUrl({ | ||||
| owner: context.repo.owner, | ||||
| repo: context.repo.repo, | ||||
| itemType: "pull_request", | ||||
| workflowCallId: callerWorkflowId, | ||||
|
||||
| workflowCallId: callerWorkflowId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
callerWorkflowIdvariable is correctly scoped here alongsideworkflowId. One suggestion: consider adding a brief JSDoc comment explaining the distinction betweenworkflowId(the stable identifier) andcallerWorkflowId(the caller-qualified ID used for history URL generation).