From b0cb8de3569837e7cab98db74677468f15c4eb27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 07:52:32 +0000 Subject: [PATCH 1/3] Initial plan From 45ea296ae1f479ad990f4c5793d472946d297ce3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 08:04:06 +0000 Subject: [PATCH 2/3] fix: add --no-fix for upgrade and exclude all .github/workflows/ files in maintenance script Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/run_operation_update_upgrade.cjs | 23 ++++-- .../js/run_operation_update_upgrade.test.cjs | 73 ++++++++++++++++--- 2 files changed, 79 insertions(+), 17 deletions(-) diff --git a/actions/setup/js/run_operation_update_upgrade.cjs b/actions/setup/js/run_operation_update_upgrade.cjs index 4098e9ab2bb..634c5c626c9 100644 --- a/actions/setup/js/run_operation_update_upgrade.cjs +++ b/actions/setup/js/run_operation_update_upgrade.cjs @@ -63,10 +63,17 @@ async function main() { const isUpgrade = operation === "upgrade"; - // Run gh aw update or gh aw upgrade (--no-compile: do not touch lock files) - const fullCmd = [bin, ...prefixArgs, operation, "--no-compile"].join(" "); + // Build command flags: + // --no-compile – do not touch lock files (always) + // --no-fix – skip codemods that would modify .md files inside + // .github/workflows/ (upgrade only). The GitHub Actions + // actor is not permitted to commit changes to workflow files. + const cmdFlags = isUpgrade ? ["--no-compile", "--no-fix"] : ["--no-compile"]; + + // Run gh aw update or gh aw upgrade with the appropriate flags + const fullCmd = [bin, ...prefixArgs, operation, ...cmdFlags].join(" "); core.info(`Running: ${fullCmd}`); - const exitCode = await exec.exec(bin, [...prefixArgs, operation, "--no-compile"]); + const exitCode = await exec.exec(bin, [...prefixArgs, operation, ...cmdFlags]); if (exitCode !== 0) { throw new Error(`Command '${fullCmd}' failed with exit code ${exitCode}`); } @@ -93,11 +100,12 @@ async function main() { return; } - // Exclude .github/workflows/*.yml files: they cannot be modified by the - // GitHub Actions bot and including them would cause the PR checks to fail. + // Exclude ALL .github/workflows/ files: the GitHub Actions actor is not + // permitted to commit any changes to workflow files (neither compiled .yml + // files nor source .md files). Including them would cause PR checks to fail. const filesToStage = changedFiles.filter(file => { const lower = file.toLowerCase(); - return !(lower.startsWith(".github/workflows/") && (lower.endsWith(".yml") || lower.endsWith(".yaml"))); + return !lower.startsWith(".github/workflows/"); }); if (filesToStage.length === 0) { @@ -182,9 +190,10 @@ async function main() { const prTitle = isUpgrade ? "[aw] Upgrade available" : "[aw] Updates available"; const fileList = stagedFiles.map(f => `- \`${f}\``).join("\n"); const operationLabel = isUpgrade ? "Upgrade" : "Update"; + const flagsStr = cmdFlags.join(" "); const prBody = `## Agentic Workflows ${operationLabel} -The \`gh aw ${operation} --no-compile\` command was run automatically and produced the following changes: +The \`gh aw ${operation} ${flagsStr}\` command was run automatically and produced the following changes: ${fileList} diff --git a/actions/setup/js/run_operation_update_upgrade.test.cjs b/actions/setup/js/run_operation_update_upgrade.test.cjs index 2a7d05d8d96..3374da32169 100644 --- a/actions/setup/js/run_operation_update_upgrade.test.cjs +++ b/actions/setup/js/run_operation_update_upgrade.test.cjs @@ -203,6 +203,24 @@ describe("run_operation_update_upgrade", () => { expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("No non-workflow files changed")); expect(mockExec.exec).not.toHaveBeenCalledWith("git", expect.arrayContaining(["add"])); }); + + it("finishes without PR when only workflow md files changed", async () => { + process.env.GH_AW_OPERATION = "update"; + process.env.GH_AW_CMD_PREFIX = "gh aw"; + process.env.GH_TOKEN = "test-token"; + + mockExec.getExecOutput = vi.fn().mockResolvedValueOnce({ + stdout: " M .github/workflows/my-workflow.md\n", + stderr: "", + exitCode: 0, + }); + + const { main } = await import("./run_operation_update_upgrade.cjs"); + await main(); + + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("No non-workflow files changed")); + expect(mockExec.exec).not.toHaveBeenCalledWith("git", expect.arrayContaining(["add"])); + }); }); describe("main - creates PR when files changed", () => { @@ -212,15 +230,15 @@ describe("run_operation_update_upgrade", () => { process.env.GH_TOKEN = "test-token"; const getExecOutputMock = vi.fn(); - // git status + // git status - only non-workflow file changed getExecOutputMock.mockResolvedValueOnce({ - stdout: " M .github/workflows/my-workflow.md\n", + stdout: " M .github/aw/actions-lock.json\n", stderr: "", exitCode: 0, }); // git diff --cached --name-only getExecOutputMock.mockResolvedValueOnce({ - stdout: ".github/workflows/my-workflow.md\n", + stdout: ".github/aw/actions-lock.json\n", stderr: "", exitCode: 0, }); @@ -240,7 +258,7 @@ describe("run_operation_update_upgrade", () => { // Verify branch was created expect(mockExec.exec).toHaveBeenCalledWith("git", expect.arrayContaining(["checkout", "-b", expect.stringContaining("aw/update-")])); // Verify file was staged - expect(mockExec.exec).toHaveBeenCalledWith("git", ["add", "--", ".github/workflows/my-workflow.md"]); + expect(mockExec.exec).toHaveBeenCalledWith("git", ["add", "--", ".github/aw/actions-lock.json"]); // Verify commit was made expect(mockExec.exec).toHaveBeenCalledWith("git", ["commit", "-m", "chore: update agentic workflows"]); // Verify PR title @@ -248,6 +266,41 @@ describe("run_operation_update_upgrade", () => { expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Created PR")); }); + it("creates PR with only non-workflow files when both workflow and non-workflow files changed", async () => { + process.env.GH_AW_OPERATION = "update"; + process.env.GH_AW_CMD_PREFIX = "gh aw"; + process.env.GH_TOKEN = "test-token"; + + // Both a workflow .md and a non-workflow file changed + const getExecOutputMock = vi.fn(); + getExecOutputMock.mockResolvedValueOnce({ + stdout: " M .github/workflows/my-workflow.md\n M .github/aw/actions-lock.json\n", + stderr: "", + exitCode: 0, + }); + // git diff --cached --name-only (only non-workflow file staged) + getExecOutputMock.mockResolvedValueOnce({ + stdout: ".github/aw/actions-lock.json\n", + stderr: "", + exitCode: 0, + }); + // gh pr create + getExecOutputMock.mockResolvedValueOnce({ + stdout: "https://github.com/testowner/testrepo/pull/5\n", + stderr: "", + exitCode: 0, + }); + mockExec.getExecOutput = getExecOutputMock; + + const { main } = await import("./run_operation_update_upgrade.cjs"); + await main(); + + // Workflow .md must NOT be staged + expect(mockExec.exec).not.toHaveBeenCalledWith("git", ["add", "--", ".github/workflows/my-workflow.md"]); + // Non-workflow file should be staged + expect(mockExec.exec).toHaveBeenCalledWith("git", ["add", "--", ".github/aw/actions-lock.json"]); + }); + it("creates PR for upgrade operation with correct title", async () => { process.env.GH_AW_OPERATION = "upgrade"; process.env.GH_AW_CMD_PREFIX = "gh aw"; @@ -277,8 +330,8 @@ describe("run_operation_update_upgrade", () => { const { main } = await import("./run_operation_update_upgrade.cjs"); await main(); - // Verify gh aw upgrade --no-compile was run - expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "upgrade", "--no-compile"]); + // Verify gh aw upgrade --no-compile --no-fix was run + expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "upgrade", "--no-compile", "--no-fix"]); // Verify correct commit message expect(mockExec.exec).toHaveBeenCalledWith("git", ["commit", "-m", "chore: upgrade agentic workflows"]); // Verify PR title is "[aw] Upgrade available" @@ -294,8 +347,8 @@ describe("run_operation_update_upgrade", () => { const getExecOutputMock = vi.fn(); getExecOutputMock - .mockResolvedValueOnce({ stdout: " M .github/workflows/my-workflow.md\n", stderr: "", exitCode: 0 }) - .mockResolvedValueOnce({ stdout: ".github/workflows/my-workflow.md\n", stderr: "", exitCode: 0 }) + .mockResolvedValueOnce({ stdout: " M .github/aw/actions-lock.json\n", stderr: "", exitCode: 0 }) + .mockResolvedValueOnce({ stdout: ".github/aw/actions-lock.json\n", stderr: "", exitCode: 0 }) .mockResolvedValueOnce({ stdout: "https://github.com/testowner/testrepo/pull/3\n", stderr: "", exitCode: 0 }); mockExec.getExecOutput = getExecOutputMock; @@ -338,7 +391,7 @@ describe("run_operation_update_upgrade", () => { const getExecOutputMock = vi.fn(); getExecOutputMock .mockResolvedValueOnce({ - stdout: " M .github/workflows/my-workflow.md\n?? .github/aw/actions-lock.json\n", + stdout: " M .github/agents/agentic-workflows.agent.md\n?? .github/aw/actions-lock.json\n", stderr: "", exitCode: 0, }) @@ -348,7 +401,7 @@ describe("run_operation_update_upgrade", () => { // git add fails for the first file, succeeds for others mockExec.exec = vi.fn().mockImplementation(async (cmd, args) => { - if (cmd === "git" && args[0] === "add" && args[2] === ".github/workflows/my-workflow.md") { + if (cmd === "git" && args[0] === "add" && args[2] === ".github/agents/agentic-workflows.agent.md") { throw new Error("git add failed"); } return 0; From fe09b3f2742dfcaa7107557fbfa575bf096160cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 08:46:40 +0000 Subject: [PATCH 3/3] fix: run update/upgrade without --no-compile/--no-fix, filter .github/workflows/ at staging Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../setup/js/run_operation_update_upgrade.cjs | 20 ++++++++----------- .../js/run_operation_update_upgrade.test.cjs | 14 ++++++------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/actions/setup/js/run_operation_update_upgrade.cjs b/actions/setup/js/run_operation_update_upgrade.cjs index 634c5c626c9..bd36efa89f0 100644 --- a/actions/setup/js/run_operation_update_upgrade.cjs +++ b/actions/setup/js/run_operation_update_upgrade.cjs @@ -63,17 +63,14 @@ async function main() { const isUpgrade = operation === "upgrade"; - // Build command flags: - // --no-compile – do not touch lock files (always) - // --no-fix – skip codemods that would modify .md files inside - // .github/workflows/ (upgrade only). The GitHub Actions - // actor is not permitted to commit changes to workflow files. - const cmdFlags = isUpgrade ? ["--no-compile", "--no-fix"] : ["--no-compile"]; - - // Run gh aw update or gh aw upgrade with the appropriate flags - const fullCmd = [bin, ...prefixArgs, operation, ...cmdFlags].join(" "); + // Run gh aw update or gh aw upgrade without extra flags so all files are + // updated (codemods, action pins, lock files, etc.). Changed files under + // .github/workflows/ are detected afterwards but excluded from staging so + // the GitHub Actions actor – which is not permitted to commit workflow + // files – does not attempt to include them in the pull request. + const fullCmd = [bin, ...prefixArgs, operation].join(" "); core.info(`Running: ${fullCmd}`); - const exitCode = await exec.exec(bin, [...prefixArgs, operation, ...cmdFlags]); + const exitCode = await exec.exec(bin, [...prefixArgs, operation]); if (exitCode !== 0) { throw new Error(`Command '${fullCmd}' failed with exit code ${exitCode}`); } @@ -190,10 +187,9 @@ async function main() { const prTitle = isUpgrade ? "[aw] Upgrade available" : "[aw] Updates available"; const fileList = stagedFiles.map(f => `- \`${f}\``).join("\n"); const operationLabel = isUpgrade ? "Upgrade" : "Update"; - const flagsStr = cmdFlags.join(" "); const prBody = `## Agentic Workflows ${operationLabel} -The \`gh aw ${operation} ${flagsStr}\` command was run automatically and produced the following changes: +The \`gh aw ${operation}\` command was run automatically and produced the following changes: ${fileList} diff --git a/actions/setup/js/run_operation_update_upgrade.test.cjs b/actions/setup/js/run_operation_update_upgrade.test.cjs index 3374da32169..5f1645f741c 100644 --- a/actions/setup/js/run_operation_update_upgrade.test.cjs +++ b/actions/setup/js/run_operation_update_upgrade.test.cjs @@ -183,7 +183,7 @@ describe("run_operation_update_upgrade", () => { await main(); expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("No changes detected")); - expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "update", "--no-compile"]); + expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "update"]); }); it("finishes without PR when only workflow yml files changed", async () => { @@ -253,8 +253,8 @@ describe("run_operation_update_upgrade", () => { const { main } = await import("./run_operation_update_upgrade.cjs"); await main(); - // Verify gh aw update --no-compile was run - expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "update", "--no-compile"]); + // Verify gh aw update was run + expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "update"]); // Verify branch was created expect(mockExec.exec).toHaveBeenCalledWith("git", expect.arrayContaining(["checkout", "-b", expect.stringContaining("aw/update-")])); // Verify file was staged @@ -330,8 +330,8 @@ describe("run_operation_update_upgrade", () => { const { main } = await import("./run_operation_update_upgrade.cjs"); await main(); - // Verify gh aw upgrade --no-compile --no-fix was run - expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "upgrade", "--no-compile", "--no-fix"]); + // Verify gh aw upgrade was run + expect(mockExec.exec).toHaveBeenCalledWith("gh", ["aw", "upgrade"]); // Verify correct commit message expect(mockExec.exec).toHaveBeenCalledWith("git", ["commit", "-m", "chore: upgrade agentic workflows"]); // Verify PR title is "[aw] Upgrade available" @@ -355,8 +355,8 @@ describe("run_operation_update_upgrade", () => { const { main } = await import("./run_operation_update_upgrade.cjs"); await main(); - // Verify binary is ./gh-aw (no prefix args) with --no-compile - expect(mockExec.exec).toHaveBeenCalledWith("./gh-aw", ["update", "--no-compile"]); + // Verify binary is ./gh-aw (no prefix args) + expect(mockExec.exec).toHaveBeenCalledWith("./gh-aw", ["update"]); }); });