name: 'Release: Patch (1) Create PR' on: workflow_dispatch: inputs: commit: description: 'The commit SHA to cherry-pick for the patch.' required: true type: 'string' channel: description: 'The release channel to patch.' required: true type: 'choice' options: - 'stable' - 'preview' dry_run: description: 'Whether to run in dry-run mode.' required: false type: 'boolean' default: false ref: description: 'The branch, tag, or SHA to test from.' required: false type: 'string' default: 'main' original_pr: description: 'The original PR number to comment back on.' required: false type: 'string' jobs: create-patch: runs-on: 'ubuntu-latest' permissions: contents: 'write' pull-requests: 'write' steps: - name: 'Checkout' uses: 'actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8' # ratchet:actions/checkout@v5 with: ref: '${{ github.event.inputs.ref }}' fetch-depth: 0 - name: 'Setup Node.js' uses: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020' # ratchet:actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'npm' - name: 'Install Dependencies' run: 'npm ci' - name: 'Configure Git User' run: |- git config user.name "gemini-cli-robot" git config user.email "gemini-cli-robot@google.com" - name: 'Generate GitHub App Token' id: 'generate_token' uses: 'actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b' with: app-id: '${{ secrets.APP_ID }}' private-key: '${{ secrets.PRIVATE_KEY }}' permission-pull-requests: 'write' permission-contents: 'write' - name: 'Create Patch for Stable' id: 'create_patch_stable' if: "github.event.inputs.channel == 'stable'" env: GH_TOKEN: '${{ steps.generate_token.outputs.token }}' continue-on-error: true run: | node scripts/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=stable --dry-run=${{ github.event.inputs.dry_run }} > patch_output.log 2>&1 echo "EXIT_CODE=$?" >> "$GITHUB_OUTPUT" cat patch_output.log - name: 'Create Patch for Preview' id: 'create_patch_preview' if: "github.event.inputs.channel != 'stable'" env: GH_TOKEN: '${{ steps.generate_token.outputs.token }}' continue-on-error: true run: | node scripts/create-patch-pr.js --commit=${{ github.event.inputs.commit }} --channel=${{ github.event.inputs.channel }} --dry-run=${{ github.event.inputs.dry_run }} > patch_output.log 2>&1 echo "EXIT_CODE=$?" >> "$GITHUB_OUTPUT" cat patch_output.log - name: 'Comment on Original PR' if: '!inputs.dry_run && inputs.original_pr' env: GH_TOKEN: '${{ steps.generate_token.outputs.token }}' run: | # Determine which step ran based on channel if [ "${{ github.event.inputs.channel }}" = "stable" ]; then EXIT_CODE="${{ steps.create_patch_stable.outputs.EXIT_CODE }}" else EXIT_CODE="${{ steps.create_patch_preview.outputs.EXIT_CODE }}" fi # Check if patch output exists and contains branch info if [ -f patch_output.log ]; then if grep -q "already exists" patch_output.log; then # Branch exists - find the PR for it BRANCH=$(grep "Hotfix branch" patch_output.log | grep "already exists" | sed 's/.*Hotfix branch \(.*\) already exists.*/\1/') # Find the PR for this branch PR_INFO=$(gh pr list --head "$BRANCH" --json number,url --jq '.[0] // empty') if [ -n "$PR_INFO" ]; then PR_NUMBER=$(echo "$PR_INFO" | jq -r '.number') PR_URL=$(echo "$PR_INFO" | jq -r '.url') MESSAGE="â„šī¸ Patch branch already exists!\n\nA patch branch already exists with an open PR: [#$PR_NUMBER]($PR_URL)\n\nPlease review and approve this existing patch PR. If it's incorrect, close it and run the patch command again." gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" else # Branch exists but no PR MESSAGE="â„šī¸ Patch branch already exists!\n\nA patch branch [\`$BRANCH\`](https://github.com/${{ github.repository }}/tree/$BRANCH) exists but has no open PR.\n\nThis might indicate an incomplete patch process. Please delete the branch and run the patch command again." gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" fi elif [ "$EXIT_CODE" = "0" ]; then # Success - find the newly created PR BRANCH=$(grep "Creating hotfix branch" patch_output.log | sed 's/.*Creating hotfix branch \(.*\) from.*/\1/') # Find the PR for the new branch PR_INFO=$(gh pr list --head "$BRANCH" --json number,url --jq '.[0] // empty') if [ -n "$PR_INFO" ]; then PR_NUMBER=$(echo "$PR_INFO" | jq -r '.number') PR_URL=$(echo "$PR_INFO" | jq -r '.url') MESSAGE="🚀 Patch PR created!\n\nThe patch release PR has been created: [#$PR_NUMBER]($PR_URL)\n\nPlease review and approve this PR to complete the patch release." gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" else # Fallback if we can't find the specific PR MESSAGE="🚀 Patch PR created!\n\nThe patch release PR for this change has been created. Please review and approve it:\n\n[View all patch PRs](https://github.com/${{ github.repository }}/pulls?q=is%3Apr+is%3Aopen+label%3Apatch)" gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" fi else # Other error MESSAGE="❌ Patch creation failed!\n\nThere was an error creating the patch. Please check the workflow logs for details:\n[View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" fi else MESSAGE="❌ Patch creation failed!\n\nNo output was generated. Please check the workflow logs:\n[View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" gh pr comment ${{ github.event.inputs.original_pr }} --body "$MESSAGE" fi