From 162ce889aabcb38e95f16fa069af99014e068be6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:07:43 +0000 Subject: [PATCH 1/4] Initial plan From 7b7589bce1ac79fbb055a72ca8ed67f2dcf13748 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:20:30 +0000 Subject: [PATCH 2/4] feat: add agentic_workflow_url substitution variable to generated-by footer Add new {agentic_workflow_url} template variable computed as {run_url}/agentic_workflow to support the new GitHub.com route for direct links to the agentic workflow file view. Update all default footer templates to use {agentic_workflow_url} instead of {run_url}: - getFooterMessage - getFooterWorkflowRecompileMessage - getFooterWorkflowRecompileCommentMessage - getFooterAgentFailureIssueMessage - getFooterAgentFailureCommentMessage The {run_url} placeholder remains available for custom templates. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/bb0cdcac-ba69-4ff1-9da0-a11d1728345b Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/messages.cjs | 1 + actions/setup/js/messages.test.cjs | 8 ++--- actions/setup/js/messages_footer.cjs | 44 ++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/actions/setup/js/messages.cjs b/actions/setup/js/messages.cjs index e8145369243..9a098a27683 100644 --- a/actions/setup/js/messages.cjs +++ b/actions/setup/js/messages.cjs @@ -17,6 +17,7 @@ * Supported placeholders: * - {workflow_name} - Name of the workflow * - {run_url} - URL to the workflow run + * - {agentic_workflow_url} - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) * - {workflow_source} - Source specification (owner/repo/path@ref) * - {workflow_source_url} - GitHub URL for the workflow source * - {triggering_number} - Issue/PR/Discussion number that triggered this workflow diff --git a/actions/setup/js/messages.test.cjs b/actions/setup/js/messages.test.cjs index e38d21b39bd..73457e2945e 100644 --- a/actions/setup/js/messages.test.cjs +++ b/actions/setup/js/messages.test.cjs @@ -165,7 +165,7 @@ describe("messages.cjs", () => { runUrl: "https://github.com/test/repo/actions/runs/123", }); - expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123)"); + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/agentic_workflow)"); }); it("should append triggering number when provided", async () => { @@ -177,7 +177,7 @@ describe("messages.cjs", () => { triggeringNumber: 42, }); - expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123) for issue #42"); + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/agentic_workflow) for issue #42"); }); it("should use custom footer template", async () => { @@ -252,7 +252,7 @@ describe("messages.cjs", () => { historyUrl: "https://github.com/search?q=repo:test/repo+is:issue&type=issues", }); - expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123) · [◷](https://github.com/search?q=repo:test/repo+is:issue&type=issues)"); + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/agentic_workflow) · [◷](https://github.com/search?q=repo:test/repo+is:issue&type=issues)"); }); it("should include both triggering number and history link when both are provided", async () => { @@ -265,7 +265,7 @@ describe("messages.cjs", () => { historyUrl: "https://github.com/search?q=repo:test/repo+is:issue&type=issues", }); - expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123) for issue #42 · [◷](https://github.com/search?q=repo:test/repo+is:issue&type=issues)"); + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/agentic_workflow) for issue #42 · [◷](https://github.com/search?q=repo:test/repo+is:issue&type=issues)"); }); it("should not append history link when historyUrl is not provided", async () => { diff --git a/actions/setup/js/messages_footer.cjs b/actions/setup/js/messages_footer.cjs index 2e41960db16..d2cc7b0f106 100644 --- a/actions/setup/js/messages_footer.cjs +++ b/actions/setup/js/messages_footer.cjs @@ -17,6 +17,7 @@ const { getDifcFilteredEvents, generateDifcFilteredSection } = require("./gatewa * @typedef {Object} FooterContext * @property {string} workflowName - Name of the workflow * @property {string} runUrl - URL of the workflow run + * @property {string} [agenticWorkflowUrl] - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) * @property {string} [workflowSource] - Source of the workflow (owner/repo/path@ref) * @property {string} [workflowSourceUrl] - GitHub URL for the workflow source * @property {number|string} [triggeringNumber] - Issue, PR, or discussion number that triggered this workflow @@ -35,8 +36,11 @@ function getFooterMessage(ctx) { // Pre-compute history_link as a ready-to-use markdown suffix (empty string when unavailable) const historyLink = ctx.historyUrl ? ` · [◷](${ctx.historyUrl})` : ""; - // Create context with both camelCase and snake_case keys, including computed history_link - const templateContext = toSnakeCase({ ...ctx, historyLink }); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + + // Create context with both camelCase and snake_case keys, including computed history_link and agentic_workflow_url + const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl }); // Use custom footer template if configured (no automatic suffix appended) if (messages?.footer) { @@ -44,7 +48,7 @@ function getFooterMessage(ctx) { } // Default footer template - includes triggering reference if available - let defaultFooter = "> Generated by [{workflow_name}]({run_url})"; + let defaultFooter = "> Generated by [{workflow_name}]({agentic_workflow_url})"; if (ctx.triggeringNumber) { defaultFooter += " for issue #{triggering_number}"; } @@ -81,6 +85,7 @@ function getFooterInstallMessage(ctx) { * @typedef {Object} WorkflowRecompileContext * @property {string} workflowName - Name of the workflow * @property {string} runUrl - URL of the workflow run + * @property {string} [agenticWorkflowUrl] - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) * @property {string} repository - Repository name (owner/repo) */ @@ -92,11 +97,14 @@ function getFooterInstallMessage(ctx) { function getFooterWorkflowRecompileMessage(ctx) { const messages = getMessages(); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + // Create context with both camelCase and snake_case keys - const templateContext = toSnakeCase(ctx); + const templateContext = toSnakeCase({ ...ctx, agenticWorkflowUrl }); // Default footer template - const defaultFooter = "> Generated by [{workflow_name}]({run_url})"; + const defaultFooter = "> Generated by [{workflow_name}]({agentic_workflow_url})"; // Use custom workflow recompile footer if configured, otherwise use default footer return messages?.footerWorkflowRecompile ? renderTemplate(messages.footerWorkflowRecompile, templateContext) : renderTemplate(defaultFooter, templateContext); @@ -110,11 +118,14 @@ function getFooterWorkflowRecompileMessage(ctx) { function getFooterWorkflowRecompileCommentMessage(ctx) { const messages = getMessages(); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + // Create context with both camelCase and snake_case keys - const templateContext = toSnakeCase(ctx); + const templateContext = toSnakeCase({ ...ctx, agenticWorkflowUrl }); // Default footer template - const defaultFooter = "> Updated by [{workflow_name}]({run_url})"; + const defaultFooter = "> Updated by [{workflow_name}]({agentic_workflow_url})"; // Use custom workflow recompile comment footer if configured, otherwise use default footer return messages?.footerWorkflowRecompileComment ? renderTemplate(messages.footerWorkflowRecompileComment, templateContext) : renderTemplate(defaultFooter, templateContext); @@ -124,6 +135,7 @@ function getFooterWorkflowRecompileCommentMessage(ctx) { * @typedef {Object} AgentFailureContext * @property {string} workflowName - Name of the workflow * @property {string} runUrl - URL of the workflow run + * @property {string} [agenticWorkflowUrl] - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) * @property {string} [workflowSource] - Source of the workflow (owner/repo/path@ref) * @property {string} [workflowSourceUrl] - GitHub URL for the workflow source * @property {string} [historyUrl] - GitHub search URL for issues created by this workflow (for the history link) @@ -140,8 +152,11 @@ function getFooterAgentFailureIssueMessage(ctx) { // Pre-compute history_link as a ready-to-use markdown suffix (empty string when unavailable) const historyLink = ctx.historyUrl ? ` · [◷](${ctx.historyUrl})` : ""; - // Create context with both camelCase and snake_case keys, including computed history_link - const templateContext = toSnakeCase({ ...ctx, historyLink }); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + + // Create context with both camelCase and snake_case keys, including computed history_link and agentic_workflow_url + const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl }); // Use custom agent failure issue footer if configured, otherwise use default footer if (messages?.agentFailureIssue) { @@ -149,7 +164,7 @@ function getFooterAgentFailureIssueMessage(ctx) { } // Default footer template with link to workflow run - let defaultFooter = "> Generated from [{workflow_name}]({run_url})"; + let defaultFooter = "> Generated from [{workflow_name}]({agentic_workflow_url})"; // Append history link when available if (ctx.historyUrl) { defaultFooter += " · [◷]({history_url})"; @@ -168,8 +183,11 @@ function getFooterAgentFailureCommentMessage(ctx) { // Pre-compute history_link as a ready-to-use markdown suffix (empty string when unavailable) const historyLink = ctx.historyUrl ? ` · [◷](${ctx.historyUrl})` : ""; - // Create context with both camelCase and snake_case keys, including computed history_link - const templateContext = toSnakeCase({ ...ctx, historyLink }); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + + // Create context with both camelCase and snake_case keys, including computed history_link and agentic_workflow_url + const templateContext = toSnakeCase({ ...ctx, historyLink, agenticWorkflowUrl }); // Use custom agent failure comment footer if configured, otherwise use default footer if (messages?.agentFailureComment) { @@ -177,7 +195,7 @@ function getFooterAgentFailureCommentMessage(ctx) { } // Default footer template with link to workflow run - let defaultFooter = "> Generated from [{workflow_name}]({run_url})"; + let defaultFooter = "> Generated from [{workflow_name}]({agentic_workflow_url})"; // Append history link when available if (ctx.historyUrl) { defaultFooter += " · [◷]({history_url})"; From 4ac08dbc83069e2d4059e9c6c2be45a0aa3f6d47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:48:26 +0000 Subject: [PATCH 3/4] fix: update TestCacheMemoryWithThreatDetection expected condition to include skipped result The test expected 'if: always() && needs.detection.result == "success"' but the compiler now generates 'if: always() && (needs.detection.result == "success" || needs.detection.result == "skipped")' since the fix in #23185. Agent-Logs-Url: https://github.com/github/gh-aw/sessions/01c4614b-2dd3-453a-94c1-59a5b1a91da4 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/cache_memory_threat_detection_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/workflow/cache_memory_threat_detection_test.go b/pkg/workflow/cache_memory_threat_detection_test.go index 4f8ae1820c6..dab50ef2463 100644 --- a/pkg/workflow/cache_memory_threat_detection_test.go +++ b/pkg/workflow/cache_memory_threat_detection_test.go @@ -53,7 +53,7 @@ Test workflow with cache-memory and threat detection enabled.`, // Should have update_cache_memory job (depends on detection job) "update_cache_memory:", "- detection", - "if: always() && needs.detection.result == 'success'", + "if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')", "- name: Download cache-memory artifact (default)", "- name: Save cache-memory to cache (default)", "uses: actions/cache/save@", From e6403fe71a85142a7f57ead98578b9ed47fc4832 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:28:28 +0000 Subject: [PATCH 4/4] fix: address PR review comments on agentic_workflow_url - Add agenticWorkflowUrl pre-computation to getFooterInstallMessage for consistency with the other footer functions - Update messages_core.cjs doc comment to include {agentic_workflow_url} as the authoritative placeholder list - Update messages.cjs barrel-file to reference messages_core.cjs instead of duplicating the placeholder list - Add unit tests for {agentic_workflow_url} in custom templates and explicit agenticWorkflowUrl context override Agent-Logs-Url: https://github.com/github/gh-aw/sessions/912f0e19-ceac-4fda-9ad3-e2cce70317b9 Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/messages.cjs | 14 +++----------- actions/setup/js/messages.test.cjs | 28 ++++++++++++++++++++++++++++ actions/setup/js/messages_core.cjs | 1 + actions/setup/js/messages_footer.cjs | 7 +++++-- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/actions/setup/js/messages.cjs b/actions/setup/js/messages.cjs index 9a098a27683..b8c884b42ea 100644 --- a/actions/setup/js/messages.cjs +++ b/actions/setup/js/messages.cjs @@ -14,18 +14,10 @@ * - ./messages_run_status.cjs - Run status messages (getRunStartedMessage, getRunSuccessMessage, getRunFailureMessage) * - ./messages_close_discussion.cjs - Close discussion messages (getCloseOlderDiscussionMessage) * - * Supported placeholders: - * - {workflow_name} - Name of the workflow - * - {run_url} - URL to the workflow run - * - {agentic_workflow_url} - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) - * - {workflow_source} - Source specification (owner/repo/path@ref) - * - {workflow_source_url} - GitHub URL for the workflow source - * - {triggering_number} - Issue/PR/Discussion number that triggered this workflow - * - {operation} - Operation name (for staged mode titles/descriptions) - * - {event_type} - Event type description (for run-started messages) - * - {status} - Workflow status text (for run-failure messages) - * + * This module supports placeholder-based templates for messages. * Both camelCase and snake_case placeholder formats are supported. + * For the authoritative and up-to-date list of supported placeholders, + * see the documentation in ./messages_core.cjs. */ // Re-export core utilities diff --git a/actions/setup/js/messages.test.cjs b/actions/setup/js/messages.test.cjs index 73457e2945e..546431a168c 100644 --- a/actions/setup/js/messages.test.cjs +++ b/actions/setup/js/messages.test.cjs @@ -312,6 +312,34 @@ describe("messages.cjs", () => { expect(result).toBe("> 🤖 *Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123)*"); expect(result).not.toContain("{history_link}"); }); + + it("should expose {agentic_workflow_url} placeholder in custom footer templates", async () => { + process.env.GH_AW_SAFE_OUTPUT_MESSAGES = JSON.stringify({ + footer: "> Generated by [{workflow_name}]({agentic_workflow_url})", + }); + + const { getFooterMessage } = await import("./messages.cjs"); + + const result = getFooterMessage({ + workflowName: "Test Workflow", + runUrl: "https://github.com/test/repo/actions/runs/123", + }); + + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/agentic_workflow)"); + }); + + it("should use explicit agenticWorkflowUrl from context instead of computing from runUrl", async () => { + const { getFooterMessage } = await import("./messages.cjs"); + + const result = getFooterMessage({ + workflowName: "Test Workflow", + runUrl: "https://github.com/test/repo/actions/runs/123", + agenticWorkflowUrl: "https://github.com/test/repo/actions/runs/123/custom_path", + }); + + expect(result).toBe("> Generated by [Test Workflow](https://github.com/test/repo/actions/runs/123/custom_path)"); + expect(result).not.toContain("/agentic_workflow"); + }); }); describe("getFooterInstallMessage", () => { diff --git a/actions/setup/js/messages_core.cjs b/actions/setup/js/messages_core.cjs index ecd4fa40e58..f31e7d8641e 100644 --- a/actions/setup/js/messages_core.cjs +++ b/actions/setup/js/messages_core.cjs @@ -10,6 +10,7 @@ * Supported placeholders: * - {workflow_name} - Name of the workflow * - {run_url} - URL to the workflow run + * - {agentic_workflow_url} - Direct URL to the agentic workflow page ({run_url}/agentic_workflow) * - {workflow_source} - Source specification (owner/repo/path@ref) * - {workflow_source_url} - GitHub URL for the workflow source * - {triggering_number} - Issue/PR/Discussion number that triggered this workflow diff --git a/actions/setup/js/messages_footer.cjs b/actions/setup/js/messages_footer.cjs index d2cc7b0f106..afc6e3e2225 100644 --- a/actions/setup/js/messages_footer.cjs +++ b/actions/setup/js/messages_footer.cjs @@ -71,8 +71,11 @@ function getFooterInstallMessage(ctx) { const messages = getMessages(); - // Create context with both camelCase and snake_case keys - const templateContext = toSnakeCase(ctx); + // Pre-compute agentic_workflow_url as the direct link to the agentic workflow page + const agenticWorkflowUrl = ctx.agenticWorkflowUrl || (ctx.runUrl ? `${ctx.runUrl}/agentic_workflow` : ""); + + // Create context with both camelCase and snake_case keys, including computed agentic_workflow_url + const templateContext = toSnakeCase({ ...ctx, agenticWorkflowUrl }); // Default installation template const defaultInstall = "> To install this [agentic workflow]({workflow_source_url}), run\n> ```\n> gh aw add {workflow_source}\n> ```";