From 454e115e3448f0d0e4fb712923306fc9934f4dba Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Thu, 30 Apr 2026 15:30:16 -0500 Subject: [PATCH] fix: use push-to-pull-request-branch instead of create-pull-request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix-review-findings was using create_pull_request to push fixes, which creates a NEW PR on a deduplicated branch name instead of pushing to the existing PR. This caused dozens of stale fix-round PRs (e.g., fix/issue-645-29d389b9). Switched to push-to-pull-request-branch which pushes commits directly to the existing PR branch — no duplicate PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../workflows/fix-review-findings.lock.yml | 100 ++++++++---------- .github/workflows/fix-review-findings.md | 26 ++--- 2 files changed, 51 insertions(+), 75 deletions(-) diff --git a/.github/workflows/fix-review-findings.lock.yml b/.github/workflows/fix-review-findings.lock.yml index fe8dbcc2f4..13ae9bbe9b 100644 --- a/.github/workflows/fix-review-findings.lock.yml +++ b/.github/workflows/fix-review-findings.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"03b9c5fee526def20da7004b0a832b3a9ae6f3018cb0be5a6b88cdf0ed1e0ee4","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.6"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8f0598860d569323f8b28ec3905b9e78ec762f3016290a744196005c0df2c7ba","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.6"} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0"},{"image":"node:lts-alpine"}]} # ___ _ _ # / _ \ | | (_) @@ -177,19 +177,19 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_cc841b27fd244cf8_EOF' + cat << 'GH_AW_PROMPT_d1219e47dfe72ce0_EOF' - GH_AW_PROMPT_cc841b27fd244cf8_EOF + GH_AW_PROMPT_d1219e47dfe72ce0_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_cc841b27fd244cf8_EOF' + cat << 'GH_AW_PROMPT_d1219e47dfe72ce0_EOF' - Tools: add_comment(max:3), create_pull_request, dispatch_workflow(max:2), missing_tool, missing_data, noop - GH_AW_PROMPT_cc841b27fd244cf8_EOF - cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_cc841b27fd244cf8_EOF' + Tools: add_comment(max:3), push_to_pull_request_branch, dispatch_workflow(max:2), missing_tool, missing_data, noop + GH_AW_PROMPT_d1219e47dfe72ce0_EOF + cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" + cat << 'GH_AW_PROMPT_d1219e47dfe72ce0_EOF' The following GitHub context information is available for this workflow: @@ -219,12 +219,12 @@ jobs: {{/if}} - GH_AW_PROMPT_cc841b27fd244cf8_EOF + GH_AW_PROMPT_d1219e47dfe72ce0_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_cc841b27fd244cf8_EOF' + cat << 'GH_AW_PROMPT_d1219e47dfe72ce0_EOF' {{#runtime-import .github/workflows/fix-review-findings.md}} - GH_AW_PROMPT_cc841b27fd244cf8_EOF + GH_AW_PROMPT_d1219e47dfe72ce0_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 @@ -399,16 +399,16 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_8f2abde834d0ebec_EOF' - {"add_comment":{"max":3,"target":"*"},"create_pull_request":{"auto_merge":false,"draft":false,"max":1,"max_patch_size":1024,"preserve_branch_name":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"]},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["expert-review"],"max":2,"workflow_files":{"expert-review":".lock.yml","verify-build":".yml"},"workflows":["expert-review","verify-build"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_8f2abde834d0ebec_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c92e0a2d5a664595_EOF' + {"add_comment":{"max":3,"target":"*"},"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["expert-review"],"max":2,"workflow_files":{"expert-review":".lock.yml","verify-build":".yml"},"workflows":["expert-review","verify-build"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"if_no_changes":"warn","max":1,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"target":"*"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_c92e0a2d5a664595_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", - "create_pull_request": " CONSTRAINTS: Maximum 1 pull request(s) can be created." + "push_to_pull_request_branch": " CONSTRAINTS: Maximum 1 push(es) can be made." }, "repo_params": {}, "dynamic_tools": [ @@ -484,42 +484,6 @@ jobs: } } }, - "create_pull_request": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "branch": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "draft": { - "type": "boolean" - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, "missing_data": { "defaultMax": 20, "fields": { @@ -577,6 +541,26 @@ jobs: } } }, + "push_to_pull_request_branch": { + "defaultMax": 1, + "fields": { + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "pull_request_number": { + "issueOrPRNumber": true + } + } + }, "report_incomplete": { "defaultMax": 5, "fields": { @@ -669,7 +653,7 @@ jobs: export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_1f61b4c4c02edf0c_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" + cat << GH_AW_MCP_CONFIG_8d523bca70e063f1_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" { "mcpServers": { "github": { @@ -710,7 +694,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_1f61b4c4c02edf0c_EOF + GH_AW_MCP_CONFIG_8d523bca70e063f1_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -1224,10 +1208,10 @@ jobs: comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} - created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }} - created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} + push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }} + push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} steps: - name: Setup Scripts id: setup @@ -1257,7 +1241,7 @@ jobs: name: agent path: /tmp/gh-aw/ - name: Checkout repository - if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }} @@ -1265,7 +1249,7 @@ jobs: persist-credentials: false fetch-depth: 1 - name: Configure Git credentials - if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') + if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') env: REPO_NAME: ${{ github.repository }} SERVER_URL: ${{ github.server_url }} @@ -1295,7 +1279,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.vsblob.vsassets.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.nuget.org,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,builds.dotnet.microsoft.com,ci.dot.net,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,dist.nuget.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkgs.dev.azure.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.microsoft.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":3,\"target\":\"*\"},\"create_pull_request\":{\"auto_merge\":false,\"draft\":false,\"max\":1,\"max_patch_size\":1024,\"preserve_branch_name\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"]},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"expert-review\"],\"max\":2,\"workflow_files\":{\"expert-review\":\".lock.yml\",\"verify-build\":\".yml\"},\"workflows\":[\"expert-review\",\"verify-build\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":3,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"expert-review\"],\"max\":2,\"workflow_files\":{\"expert-review\":\".lock.yml\",\"verify-build\":\".yml\"},\"workflows\":[\"expert-review\",\"verify-build\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":1,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/fix-review-findings.md b/.github/workflows/fix-review-findings.md index 41acb254ea..b1dd94fc74 100644 --- a/.github/workflows/fix-review-findings.md +++ b/.github/workflows/fix-review-findings.md @@ -35,10 +35,9 @@ tools: toolsets: [repos, issues, pull_requests] safe-outputs: - create-pull-request: - auto-merge: false - draft: false - preserve-branch-name: true + push-to-pull-request-branch: + max: 1 + target: "*" protected-files: fallback-to-issue add-comment: max: 3 @@ -124,32 +123,25 @@ If any tests fail, fix them before proceeding. All tests must pass. ## Step 5: Commit and Push (MANDATORY) -> **🚨 You MUST use `create_pull_request` to push your fixes.** This is the only way to push commits in a gh-aw workflow. Do NOT try `git push` directly — it will fail. +> **🚨 You MUST use `push_to_pull_request_branch` to push your fixes.** This pushes commits to the EXISTING PR branch. Do NOT use `create_pull_request` — that creates a duplicate PR. Do NOT try `git push` directly — it will fail. -Commit all fixes locally, then create a patch and push via the `create_pull_request` safe output: +Commit all fixes locally, then push to the existing PR branch: ```bash git add -A git commit -m "fix: address review findings round Co-authored-by: copilot-agentic-workflow[bot] <224017+copilot-agentic-workflow[bot]@users.noreply.github.com>" - -# Create the patch for safe-outputs -git format-patch origin/main --stdout > /tmp/gh-aw/aw-review-fixes.patch ``` -Then call `create_pull_request` to push the fixes to the existing PR branch. Use the **exact same branch name** as the existing PR (check with `get_pull_request` if needed). The `preserve-branch-name: true` setting ensures the branch name is kept as-is. - -> **🚨 Do NOT pass a `base` field.** The base branch is inherited. Passing `base` causes a "Base branch override is not allowed" error that cancels all safe outputs. +Then call `push_to_pull_request_branch` to push your commits to PR #${{ inputs.pr_number }}: ``` -create_pull_request({ - "title": "fix: address review findings round (PR #${{ inputs.pr_number }})", - "body": "Addresses review findings from expert review round .", - "head": "" -}) +push_to_pull_request_branch({ "pr_number": "${{ inputs.pr_number }}" }) ``` +This pushes all local commits to the existing PR's branch — no new PR is created. + ## Step 6: Re-dispatch Expert Review (MANDATORY if detected round < 3) Use the auto-detected round number from Step 1 (not `${{ inputs.round }}`).