diff --git a/.changeset/patch-fix-safe-outputs-apply.md b/.changeset/patch-fix-safe-outputs-apply.md new file mode 100644 index 00000000000..b1a684e5da4 --- /dev/null +++ b/.changeset/patch-fix-safe-outputs-apply.md @@ -0,0 +1,14 @@ +--- +"gh-aw": patch +--- + +Fix: Ensure `create-pull-request` and `push-to-pull-request-branch` safe outputs +are applied correctly by downloading the patch artifact, checking out the +repository, configuring git, and using the appropriate token when available. + +This is an internal tooling fix for action workflows; it does not change the +public CLI API. + +-- +PR: #7167 + diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 959928d6979..30eced9bd53 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -7482,6 +7482,12 @@ jobs: permission-contents: write permission-issues: write permission-pull-requests: write + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8820,6 +8826,25 @@ jobs: executeUpdate: executePRUpdate, }); (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ steps.app-token.outputs.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + 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 }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ steps.app-token.outputs.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Push To Pull Request Branch id: push_to_pull_request_branch if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) @@ -8984,16 +9009,19 @@ jobs: let branchName; let prTitle = ""; let prLabels = []; + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index a3fd0d36cc7..a38f5d3297f 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -7292,6 +7292,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7561,6 +7567,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index a104933143e..5d90241101b 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -7539,6 +7539,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8385,6 +8391,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 1e45316d153..4792b06926c 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -7646,6 +7646,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8854,6 +8860,25 @@ jobs: return createdComments; } (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + 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 }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Push To Pull Request Branch id: push_to_pull_request_branch if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) @@ -9017,16 +9042,19 @@ jobs: let branchName; let prTitle = ""; let prLabels = []; + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index ccbbe7d49ba..3d5803aa28f 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -6279,6 +6279,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6548,6 +6554,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml index 866a032c28d..a4971c33fab 100644 --- a/.github/workflows/daily-workflow-updater.lock.yml +++ b/.github/workflows/daily-workflow-updater.lock.yml @@ -6549,6 +6549,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6818,6 +6824,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 30903bfab44..ee52fb9124e 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -6831,6 +6831,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8154,6 +8160,25 @@ jobs: core.info(`Successfully created ${createdDiscussions.length} discussion(s)`); } (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 558d307d0b9..d9a94b16061 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -6444,6 +6444,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6713,6 +6719,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 0f9d99c9443..05b6bbc4093 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -6642,6 +6642,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7965,6 +7971,25 @@ jobs: core.info(`Successfully created ${createdDiscussions.length} discussion(s)`); } (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 5fda8cd5174..7f64e063c72 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -7137,6 +7137,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7406,6 +7412,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index a6abe873a52..a19caf300c1 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -6353,6 +6353,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6622,6 +6628,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml index 36503e438ca..b0e5bacd54f 100644 --- a/.github/workflows/hourly-ci-cleaner.lock.yml +++ b/.github/workflows/hourly-ci-cleaner.lock.yml @@ -6775,6 +6775,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7044,6 +7050,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/incident-response.lock.yml b/.github/workflows/incident-response.lock.yml index f3a28a4a205..09d992061cc 100644 --- a/.github/workflows/incident-response.lock.yml +++ b/.github/workflows/incident-response.lock.yml @@ -7265,6 +7265,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -9259,6 +9265,25 @@ jobs: (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 9de726e6e93..540b25fd7c5 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -6233,6 +6233,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6502,6 +6508,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index 5a8a0bba37a..8ad4c0b71c8 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -6647,6 +6647,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6916,6 +6922,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml index abcac790503..26f9cafb2a5 100644 --- a/.github/workflows/layout-spec-maintainer.lock.yml +++ b/.github/workflows/layout-spec-maintainer.lock.yml @@ -6667,6 +6667,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6936,6 +6942,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 8d1e6e0081d..d898936764f 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -7356,6 +7356,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7557,6 +7563,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + 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 }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Push To Pull Request Branch id: push_to_pull_request_branch if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) @@ -7720,16 +7745,19 @@ jobs: let branchName; let prTitle = ""; let prLabels = []; + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/org-wide-rollout.lock.yml b/.github/workflows/org-wide-rollout.lock.yml index 265cbc983bb..7db55a975c4 100644 --- a/.github/workflows/org-wide-rollout.lock.yml +++ b/.github/workflows/org-wide-rollout.lock.yml @@ -7293,6 +7293,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -9287,6 +9293,25 @@ jobs: (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index c557f9cfbda..1ed65768a47 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -8030,6 +8030,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -11548,6 +11554,25 @@ jobs: core.info(`Successfully created ${createdDiscussions.length} discussion(s)`); } (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) @@ -12900,6 +12925,25 @@ jobs: executeUpdate: executeIssueUpdate, }); (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + 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 }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Push To Pull Request Branch id: push_to_pull_request_branch if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) @@ -13064,16 +13108,19 @@ jobs: let branchName; let prTitle = ""; let prLabels = []; + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 80a5d3e336f..75c8c9564bd 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -7940,6 +7940,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8786,6 +8792,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 64935534d11..a73458ace5b 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -6443,6 +6443,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -6712,6 +6718,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml index 35788ca0309..2f0b600185f 100644 --- a/.github/workflows/slide-deck-maintainer.lock.yml +++ b/.github/workflows/slide-deck-maintainer.lock.yml @@ -6941,6 +6941,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7210,6 +7216,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/spec-kit-execute.lock.yml b/.github/workflows/spec-kit-execute.lock.yml index 2a11bdcc27a..35bf0e874c9 100644 --- a/.github/workflows/spec-kit-execute.lock.yml +++ b/.github/workflows/spec-kit-execute.lock.yml @@ -7043,6 +7043,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7312,6 +7318,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/spec-kit-executor.lock.yml b/.github/workflows/spec-kit-executor.lock.yml index 599dad539fb..4cc2210414c 100644 --- a/.github/workflows/spec-kit-executor.lock.yml +++ b/.github/workflows/spec-kit-executor.lock.yml @@ -6918,6 +6918,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7187,6 +7193,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 619e24b03f3..e4d2a0c3bd8 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -6952,6 +6952,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7798,6 +7804,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index adfe24f27af..e17013db656 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -7164,6 +7164,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -7471,6 +7477,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) @@ -7974,6 +7999,25 @@ jobs: } } (async () => { await main(); })(); + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + 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 }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Push To Pull Request Branch id: push_to_pull_request_branch if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) @@ -8137,16 +8181,19 @@ jobs: let branchName; let prTitle = ""; let prLabels = []; + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); core.setFailed(`Failed to determine branch name for PR ${pullNumber}`); diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 4f1778bde8e..7dfea21a325 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -7157,6 +7157,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: aw.patch + path: /tmp/gh-aw/ - name: Setup JavaScript files id: setup_scripts shell: bash @@ -8003,6 +8009,25 @@ jobs: }; EOF_967a5011 + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 0 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Create Pull Request id: create_pull_request if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) diff --git a/pkg/workflow/compile_outputs_pr_test.go b/pkg/workflow/compile_outputs_pr_test.go index b1848b32a92..b77c105114c 100644 --- a/pkg/workflow/compile_outputs_pr_test.go +++ b/pkg/workflow/compile_outputs_pr_test.go @@ -432,3 +432,76 @@ This workflow tests the default if-no-changes behavior. t.Error("Expected GH_AW_PR_IF_NO_CHANGES environment variable to be set in generated workflow") } } + +// TestCreatePullRequestPatchArtifactDownload verifies that when create-pull-request +// is enabled, the safe_outputs job includes a step to download the aw.patch artifact +func TestCreatePullRequestPatchArtifactDownload(t *testing.T) { + // Create a temporary directory for the test + tmpDir := testutil.TempDir(t, "test-*") + + // Create a test markdown file with create-pull-request configuration + testMarkdown := `--- +on: + pull_request: + types: [opened] +safe-outputs: + create-pull-request: + title-prefix: "[bot] " +--- + +# Test Create Pull Request Patch Download + +This test verifies that the aw.patch artifact is downloaded in the safe_outputs job. +` + + // Write the test file + mdFile := filepath.Join(tmpDir, "test-create-pr-patch-download.md") + if err := os.WriteFile(mdFile, []byte(testMarkdown), 0644); err != nil { + t.Fatalf("Failed to write test markdown file: %v", err) + } + + // Create compiler and compile the workflow + compiler := NewCompiler(false, "", "test") + + if err := compiler.CompileWorkflow(mdFile); err != nil { + t.Fatalf("Failed to compile workflow: %v", err) + } + + // Read the generated .lock.yml file + lockFile := strings.TrimSuffix(mdFile, ".md") + ".lock.yml" + lockContent, err := os.ReadFile(lockFile) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + + lockContentStr := string(lockContent) + + // Verify that safe_outputs job exists + if !strings.Contains(lockContentStr, "safe_outputs:") { + t.Fatalf("Generated workflow should contain safe_outputs job") + } + + // Verify that patch download step exists in safe_outputs job + if !strings.Contains(lockContentStr, "- name: Download patch artifact") { + t.Errorf("Expected 'Download patch artifact' step in safe_outputs job when create-pull-request is enabled") + } + + // Verify that patch is downloaded to correct path + if !strings.Contains(lockContentStr, "name: aw.patch") { + t.Errorf("Expected patch artifact to be named 'aw.patch'") + } + + if !strings.Contains(lockContentStr, "path: /tmp/gh-aw/") { + t.Errorf("Expected patch artifact to be downloaded to '/tmp/gh-aw/'") + } + + // Verify that the create_pull_request step exists + if !strings.Contains(lockContentStr, "- name: Create Pull Request") { + t.Errorf("Expected 'Create Pull Request' step in safe_outputs job") + } + + // Verify that the condition checks for create_pull_request output type + if !strings.Contains(lockContentStr, "contains(needs.agent.outputs.output_types, 'create_pull_request')") { + t.Errorf("Expected condition to check for 'create_pull_request' in output_types") + } +} diff --git a/pkg/workflow/compiler_safe_outputs_consolidated.go b/pkg/workflow/compiler_safe_outputs_consolidated.go index ab5d065e49c..47c631887b7 100644 --- a/pkg/workflow/compiler_safe_outputs_consolidated.go +++ b/pkg/workflow/compiler_safe_outputs_consolidated.go @@ -153,6 +153,19 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa // Add artifact download steps once at the beginning steps = append(steps, buildAgentOutputDownloadSteps()...) + // Add patch artifact download if create-pull-request or push-to-pull-request-branch is enabled + // Both of these safe outputs require the patch file to apply changes + if data.SafeOutputs.CreatePullRequests != nil || data.SafeOutputs.PushToPullRequestBranch != nil { + consolidatedSafeOutputsLog.Print("Adding patch artifact download for create-pull-request or push-to-pull-request-branch") + patchDownloadSteps := buildArtifactDownloadSteps(ArtifactDownloadConfig{ + ArtifactName: "aw.patch", + DownloadPath: "/tmp/gh-aw/", + SetupEnvStep: false, // No environment variable needed, the script checks the file directly + StepName: "Download patch artifact", + }) + steps = append(steps, patchDownloadSteps...) + } + // Add JavaScript files setup step if using file mode if scriptFilesResult != nil && len(scriptFilesResult.Files) > 0 { // Prepare files with rewritten require paths @@ -1254,14 +1267,102 @@ func (c *Compiler) buildUpdateProjectStepConfig(data *WorkflowData, mainJobName // buildCreatePullRequestPreSteps builds the pre-steps for create-pull-request func (c *Compiler) buildCreatePullRequestPreStepsConsolidated(data *WorkflowData, cfg *CreatePullRequestsConfig, condition ConditionNode) []string { - // This is a simplified version - the actual implementation would include - // checkout, git config, and patch application steps - return nil + var preSteps []string + + // Determine which token to use for checkout + // If an app is configured, use the app token; otherwise use the default github.token + var checkoutToken string + var gitRemoteToken string + if data.SafeOutputs.App != nil { + checkoutToken = "${{ steps.app-token.outputs.token }}" + gitRemoteToken = "${{ steps.app-token.outputs.token }}" + } else { + checkoutToken = "${{ github.token }}" + gitRemoteToken = "${{ github.token }}" + } + + // Step 1: Checkout repository with conditional execution + preSteps = append(preSteps, " - name: Checkout repository\n") + // Add the condition to only checkout if create_pull_request will run + preSteps = append(preSteps, fmt.Sprintf(" if: %s\n", condition.Render())) + preSteps = append(preSteps, fmt.Sprintf(" uses: %s\n", GetActionPin("actions/checkout"))) + preSteps = append(preSteps, " with:\n") + preSteps = append(preSteps, fmt.Sprintf(" token: %s\n", checkoutToken)) + preSteps = append(preSteps, " persist-credentials: false\n") + preSteps = append(preSteps, " fetch-depth: 0\n") + if c.trialMode { + if c.trialLogicalRepoSlug != "" { + preSteps = append(preSteps, fmt.Sprintf(" repository: %s\n", c.trialLogicalRepoSlug)) + } + } + + // Step 2: Configure Git credentials with conditional execution + gitConfigSteps := []string{ + " - name: Configure Git credentials\n", + fmt.Sprintf(" if: %s\n", condition.Render()), + " env:\n", + " REPO_NAME: ${{ github.repository }}\n", + " SERVER_URL: ${{ github.server_url }}\n", + " run: |\n", + " git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n", + " git config --global user.name \"github-actions[bot]\"\n", + " # Re-authenticate git with GitHub token\n", + " SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n", + fmt.Sprintf(" git remote set-url origin \"https://x-access-token:%s@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n", gitRemoteToken), + " echo \"Git configured with standard GitHub Actions identity\"\n", + } + preSteps = append(preSteps, gitConfigSteps...) + + return preSteps } // buildPushToPullRequestBranchPreSteps builds the pre-steps for push-to-pull-request-branch func (c *Compiler) buildPushToPullRequestBranchPreStepsConsolidated(data *WorkflowData, cfg *PushToPullRequestBranchConfig, condition ConditionNode) []string { - // This is a simplified version - the actual implementation would include - // checkout and git config steps - return nil + var preSteps []string + + // Determine which token to use for checkout + // If an app is configured, use the app token; otherwise use the default github.token + var checkoutToken string + var gitRemoteToken string + if data.SafeOutputs.App != nil { + checkoutToken = "${{ steps.app-token.outputs.token }}" + gitRemoteToken = "${{ steps.app-token.outputs.token }}" + } else { + checkoutToken = "${{ github.token }}" + gitRemoteToken = "${{ github.token }}" + } + + // Step 1: Checkout repository with conditional execution + preSteps = append(preSteps, " - name: Checkout repository\n") + // Add the condition to only checkout if push_to_pull_request_branch will run + preSteps = append(preSteps, fmt.Sprintf(" if: %s\n", condition.Render())) + preSteps = append(preSteps, fmt.Sprintf(" uses: %s\n", GetActionPin("actions/checkout"))) + preSteps = append(preSteps, " with:\n") + preSteps = append(preSteps, fmt.Sprintf(" token: %s\n", checkoutToken)) + preSteps = append(preSteps, " persist-credentials: false\n") + preSteps = append(preSteps, " fetch-depth: 0\n") + if c.trialMode { + if c.trialLogicalRepoSlug != "" { + preSteps = append(preSteps, fmt.Sprintf(" repository: %s\n", c.trialLogicalRepoSlug)) + } + } + + // Step 2: Configure Git credentials with conditional execution + gitConfigSteps := []string{ + " - name: Configure Git credentials\n", + fmt.Sprintf(" if: %s\n", condition.Render()), + " env:\n", + " REPO_NAME: ${{ github.repository }}\n", + " SERVER_URL: ${{ github.server_url }}\n", + " run: |\n", + " git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n", + " git config --global user.name \"github-actions[bot]\"\n", + " # Re-authenticate git with GitHub token\n", + " SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n", + fmt.Sprintf(" git remote set-url origin \"https://x-access-token:%s@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n", gitRemoteToken), + " echo \"Git configured with standard GitHub Actions identity\"\n", + } + preSteps = append(preSteps, gitConfigSteps...) + + return preSteps } diff --git a/pkg/workflow/js/push_to_pull_request_branch.cjs b/pkg/workflow/js/push_to_pull_request_branch.cjs index 8b3f6afe0cb..a333318f110 100644 --- a/pkg/workflow/js/push_to_pull_request_branch.cjs +++ b/pkg/workflow/js/push_to_pull_request_branch.cjs @@ -200,17 +200,22 @@ async function main() { let prTitle = ""; let prLabels = []; + // Validate pull number is defined before fetching + if (!pullNumber) { + core.setFailed("Pull request number is required but not found"); + return; + } + // Fetch the specific PR to get its head branch, title, and labels try { - const prInfoRes = await exec.getExecOutput(`gh`, [`pr`, `view`, `${pullNumber}`, `--json`, `headRefName,title,labels`, `--jq`, `{headRefName, title, labels: (.labels // [] | map(.name))}`]); - if (prInfoRes.exitCode === 0) { - const prData = JSON.parse(prInfoRes.stdout.trim()); - branchName = prData.headRefName; - prTitle = prData.title || ""; - prLabels = prData.labels || []; - } else { - throw new Error("No PR data found"); - } + const { data: pullRequest } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pullNumber + }); + branchName = pullRequest.head.ref; + prTitle = pullRequest.title || ""; + prLabels = pullRequest.labels.map(label => label.name); } catch (error) { core.info(`Warning: Could not fetch PR ${pullNumber} details: ${error instanceof Error ? error.message : String(error)}`); // Exit with failure if we cannot determine the branch name diff --git a/pkg/workflow/js/push_to_pull_request_branch.test.cjs b/pkg/workflow/js/push_to_pull_request_branch.test.cjs index 9365097dcb6..8ce269d370b 100644 --- a/pkg/workflow/js/push_to_pull_request_branch.test.cjs +++ b/pkg/workflow/js/push_to_pull_request_branch.test.cjs @@ -29,7 +29,21 @@ const mockCore = { summary: { addRaw: vi.fn().mockReturnThis(), write: vi.fn().mockResolvedValue() }, }, mockContext = { eventName: "pull_request", payload: { pull_request: { number: 123 }, repository: { html_url: "https://github.com/testowner/testrepo" } }, repo: { owner: "testowner", repo: "testrepo" } }, - mockGithub = { graphql: vi.fn(), request: vi.fn() }; + mockGithub = { + graphql: vi.fn(), + request: vi.fn(), + rest: { + pulls: { + get: vi.fn().mockResolvedValue({ + data: { + head: { ref: "feature-branch" }, + title: "Test PR Title", + labels: [{ name: "bug" }, { name: "enhancement" }] + } + }) + } + } + }; ((global.core = mockCore), (global.context = mockContext), (global.github = mockGithub), @@ -64,10 +78,6 @@ const mockCore = { (mockExec = { exec: vi.fn().mockResolvedValue(0), getExecOutput: vi.fn().mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1] && args.includes("--json") && args.includes("headRefName,title,labels")) { - const prData = JSON.stringify({ headRefName: "feature-branch", title: "Test PR Title", labels: ["bug", "enhancement"] }); - return Promise.resolve({ exitCode: 0, stdout: prData + "\n", stderr: "" }); - } return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), }), @@ -242,12 +252,12 @@ const mockCore = { (process.env.GH_AW_PR_TITLE_PREFIX = "[bot] "), mockFs.existsSync.mockReturnValue(!0), mockPatchContent("diff --git a/file.txt b/file.txt\n+new content"), - mockExec.getExecOutput.mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "[bot] Add new feature", labels: [] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData), stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "[bot] Add new feature", + labels: [] } - return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), await executeScript(), expect(mockCore.info).toHaveBeenCalledWith('✓ Title prefix validation passed: "[bot] "'), @@ -258,12 +268,12 @@ const mockCore = { (process.env.GH_AW_PR_TITLE_PREFIX = "[bot] "), mockFs.existsSync.mockReturnValue(!0), mockPatchContent("diff --git a/file.txt b/file.txt\n+new content"), - mockExec.getExecOutput.mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "Add new feature", labels: [] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData), stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "Add new feature", + labels: [] } - return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), await executeScript(), expect(mockCore.setFailed).toHaveBeenCalledWith('Pull request title "Add new feature" does not start with required prefix "[bot] "')); @@ -273,12 +283,12 @@ const mockCore = { (process.env.GH_AW_PR_LABELS = "automation,enhancement"), mockFs.existsSync.mockReturnValue(!0), mockPatchContent("diff --git a/file.txt b/file.txt\n+new content"), - mockExec.getExecOutput.mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "Add new feature", labels: ["automation", "enhancement", "feature"] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData), stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "Add new feature", + labels: [{ name: "automation" }, { name: "enhancement" }, { name: "feature" }] } - return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), await executeScript(), expect(mockCore.info).toHaveBeenCalledWith("✓ Labels validation passed: automation,enhancement"), @@ -289,12 +299,12 @@ const mockCore = { (process.env.GH_AW_PR_LABELS = "automation,enhancement"), mockFs.existsSync.mockReturnValue(!0), mockPatchContent("diff --git a/file.txt b/file.txt\n+new content"), - mockExec.getExecOutput.mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "Add new feature", labels: ["feature"] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData), stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "Add new feature", + labels: [{ name: "feature" }] } - return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), await executeScript(), expect(mockCore.setFailed).toHaveBeenCalledWith("Pull request is missing required labels: automation, enhancement. Current labels: feature")); @@ -305,12 +315,12 @@ const mockCore = { (process.env.GH_AW_PR_LABELS = "bot,feature"), mockFs.existsSync.mockReturnValue(!0), mockPatchContent("diff --git a/file.txt b/file.txt\n+new content"), - mockExec.getExecOutput.mockImplementation((command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "[automated] Add new feature", labels: ["bot", "feature", "enhancement"] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData), stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "[automated] Add new feature", + labels: [{ name: "bot" }, { name: "feature" }, { name: "enhancement" }] } - return "git" === command && args && "rev-parse" === args[0] && "HEAD" === args[1] ? Promise.resolve({ exitCode: 0, stdout: "abc123def456\n", stderr: "" }) : Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), await executeScript(), expect(mockCore.info).toHaveBeenCalledWith('✓ Title prefix validation passed: "[automated] "'), @@ -390,11 +400,14 @@ const mockCore = { if ("string" == typeof cmd && cmd.includes("git am")) throw ((gitAmCalled = !0), new Error("Patch does not apply")); return 0; }), - mockExec.getExecOutput.mockImplementation(async (command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "Test PR Title", labels: ["bug", "enhancement"] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData) + "\n", stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "Test PR Title", + labels: [{ name: "bug" }, { name: "enhancement" }] } + }), + mockExec.getExecOutput.mockImplementation(async (command, args) => { return "git" === command && args && "status" === args[0] ? Promise.resolve({ exitCode: 0, stdout: "On branch feature-branch\nYour branch is up to date\n", stderr: "" }) : "git" === command && args && "log" === args[0] && "--oneline" === args[1] && "-5" === args[2] @@ -435,11 +448,14 @@ const mockCore = { if ("string" == typeof cmd && cmd.includes("git am")) throw new Error("Patch does not apply"); return 0; }), - mockExec.getExecOutput.mockImplementation(async (command, args) => { - if ("gh" === command && args && "pr" === args[0] && "view" === args[1]) { - const prData = { headRefName: "feature-branch", title: "Test PR Title", labels: [] }; - return Promise.resolve({ exitCode: 0, stdout: JSON.stringify(prData) + "\n", stderr: "" }); + mockGithub.rest.pulls.get.mockResolvedValueOnce({ + data: { + head: { ref: "feature-branch" }, + title: "Test PR Title", + labels: [] } + }), + mockExec.getExecOutput.mockImplementation(async (command, args) => { if ("git" === command) throw new Error("Git command failed"); return Promise.resolve({ exitCode: 0, stdout: "", stderr: "" }); }), diff --git a/pkg/workflow/push_to_pull_request_branch_test.go b/pkg/workflow/push_to_pull_request_branch_test.go index e8615b5166a..44cc6834a7f 100644 --- a/pkg/workflow/push_to_pull_request_branch_test.go +++ b/pkg/workflow/push_to_pull_request_branch_test.go @@ -804,3 +804,75 @@ Test that the push-to-pull-request-branch job receives activation comment enviro t.Errorf("Generated workflow should contain GH_AW_COMMENT_REPO environment variable") } } + +// TestPushToPullRequestBranchPatchArtifactDownload verifies that when push-to-pull-request-branch +// is enabled, the safe_outputs job includes a step to download the aw.patch artifact +func TestPushToPullRequestBranchPatchArtifactDownload(t *testing.T) { + // Create a temporary directory for the test + tmpDir := testutil.TempDir(t, "test-*") + + // Create a test markdown file with push-to-pull-request-branch configuration + testMarkdown := `--- +on: + pull_request: + types: [opened] +safe-outputs: + push-to-pull-request-branch: +--- + +# Test Push to PR Branch Patch Download + +This test verifies that the aw.patch artifact is downloaded in the safe_outputs job. +` + + // Write the test file + mdFile := filepath.Join(tmpDir, "test-push-patch-download.md") + if err := os.WriteFile(mdFile, []byte(testMarkdown), 0644); err != nil { + t.Fatalf("Failed to write test markdown file: %v", err) + } + + // Create compiler and compile the workflow + compiler := NewCompiler(false, "", "test") + + if err := compiler.CompileWorkflow(mdFile); err != nil { + t.Fatalf("Failed to compile workflow: %v", err) + } + + // Read the generated .lock.yml file + lockFile := strings.TrimSuffix(mdFile, ".md") + ".lock.yml" + lockContent, err := os.ReadFile(lockFile) + if err != nil { + t.Fatalf("Failed to read lock file: %v", err) + } + + lockContentStr := string(lockContent) + + // Verify that safe_outputs job exists + if !strings.Contains(lockContentStr, "safe_outputs:") { + t.Fatalf("Generated workflow should contain safe_outputs job") + } + + // Verify that patch download step exists in safe_outputs job + if !strings.Contains(lockContentStr, "- name: Download patch artifact") { + t.Errorf("Expected 'Download patch artifact' step in safe_outputs job when push-to-pull-request-branch is enabled") + } + + // Verify that patch is downloaded to correct path + if !strings.Contains(lockContentStr, "name: aw.patch") { + t.Errorf("Expected patch artifact to be named 'aw.patch'") + } + + if !strings.Contains(lockContentStr, "path: /tmp/gh-aw/") { + t.Errorf("Expected patch artifact to be downloaded to '/tmp/gh-aw/'") + } + + // Verify that the push step exists and references the patch file + if !strings.Contains(lockContentStr, "- name: Push To Pull Request Branch") { + t.Errorf("Expected 'Push To Pull Request Branch' step in safe_outputs job") + } + + // Verify that the condition checks for push_to_pull_request_branch output type + if !strings.Contains(lockContentStr, "contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')") { + t.Errorf("Expected condition to check for 'push_to_pull_request_branch' in output_types") + } +}