# This workflow is used to cherry pick PRs into a frozen release branch. name: New PRR workflow - Cherry pick on: pull_request: types: [closed] workflow_dispatch: inputs: skipSlackPing: description: 'Skip Slack Ping: If true, the Slack ping will be skipped (useful for testing)' type: boolean required: false default: false env: GIT_COMMITTER_NAME: 'WooCommerce Bot' GIT_COMMITTER_EMAIL: 'no-reply@woocommerce.com' GIT_AUTHOR_NAME: 'WooCommerce Bot' GIT_AUTHOR_EMAIL: 'no-reply@woocommerce.com' permissions: {} jobs: verify: name: Verify runs-on: ubuntu-20.04 outputs: run: ${{ steps.check.outputs.run }} base_ref: ${{ steps.fetch_pr_details.outputs.base_ref }} steps: - name: Fetch Pull Request Details if: github.event.pull_request id: fetch_pr_details uses: actions/github-script@v7 with: script: | const pullRequestUrl = context.payload.pull_request.url; const prDetails = await github.request(pullRequestUrl); const labels = prDetails.data.labels.map(label => label.name); console.log('Labels:', labels); if (!labels.includes('cherry pick to frozen release')) { console.log('Label "cherry pick to frozen release" not found. Exiting job.'); process.exit(0); } core.setOutput('base_ref', prDetails.data.base.ref); env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: check id: check uses: actions/github-script@v7 with: script: | const baseRef = process.env.BASE_REF; console.log("baseRef:", baseRef); let run = false; const isBot = context.payload.pull_request && ( context.payload.pull_request.user.login == 'github-actions[bot]' || context.payload.pull_request.user.type == 'Bot' ); console.log("isBot:", isBot); console.log("baseRef.startsWith('release/'):", baseRef.startsWith('release/')); if ( !isBot && baseRef.startsWith( 'release/' ) ) { core.setOutput( 'run', 'true' ); } else { core.setOutput( 'run', 'false' ); } env: BASE_REF: ${{ steps.fetch_pr_details.outputs.base_ref }} prep: name: Prep inputs runs-on: ubuntu-20.04 if: needs.verify.outputs.run == 'true' needs: verify outputs: release: ${{ steps.prep-inputs.outputs.release }} frozenRelease: ${{ steps.prep-inputs.outputs.frozenRelease }} pr: ${{ steps.prep-inputs.outputs.pr }} version: ${{ steps.prep-inputs.outputs.version }} steps: - name: Prep inputs id: prep-inputs uses: actions/github-script@v7 with: script: | const event = ${{ toJSON( github.event ) }} const releaseBranch = process.env.BASE_REF const version = releaseBranch.replace( 'release/', '' ) const pr = event.pull_request.number // Split the version to get major and minor parts let [major, minor] = version.split('.').map(Number) // Check if minor version is 9, increment major and reset minor if (minor === 9) { major += 1 minor = 0 } else { // Otherwise, just increment the minor version minor += 1 } // Create the frozen release branch name const frozenRelease = `release/${major}.${minor}` // Output the values console.log('releaseBranch:', releaseBranch) console.log('version:', version) console.log('pr:', pr) console.log('frozenRelease:', frozenRelease) core.setOutput('pr', pr) core.setOutput('version', version) core.setOutput('release', releaseBranch) core.setOutput('frozenRelease', frozenRelease) env: BASE_REF: ${{ needs.verify.outputs.base_ref }} check-release-branch-exists: name: Check for existence of release branch runs-on: ubuntu-20.04 needs: prep steps: - name: Check for release branch id: release-breanch-check uses: actions/github-script@v7 with: script: | // This will throw an error for non-200 responses, which prevents subsequent jobs from completing, as desired. await github.request( 'GET /repos/{owner}/{repo}/branches/{branch}', { owner: context.repo.owner, repo: context.repo.repo, branch: process.env.RELEASE_BRANCH, } ); env: RELEASE_BRANCH: ${{ needs.prep.outputs.release }} check-frozen-release-branch-exists: name: Check for existence of frozen release branch runs-on: ubuntu-20.04 needs: prep steps: - name: Check for release branch id: release-breanch-check uses: actions/github-script@v7 with: script: | // This will throw an error for non-200 responses, which prevents subsequent jobs from completing, as desired. await github.request( 'GET /repos/{owner}/{repo}/branches/{branch}', { owner: context.repo.owner, repo: context.repo.repo, branch: process.env.FROZEN_RELEASE_BRANCH, } ); env: FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} cherry-pick-run: name: Run cherry pick tool runs-on: ubuntu-20.04 permissions: actions: write contents: write pull-requests: write needs: [prep, check-release-branch-exists, check-frozen-release-branch-exists] if: success() steps: - name: Checkout release branch uses: actions/checkout@v3 with: fetch-depth: 0 - name: Git fetch the frozen release branch run: git fetch origin $FROZEN_RELEASE_BRANCH env: FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} - name: Checkout frozen release branch run: git checkout $FROZEN_RELEASE_BRANCH env: FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} - name: Create a cherry pick branch run: git checkout -b cherry-pick-$FROZEN_RELEASE_BRANCH/$PR env: FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} PR: ${{ needs.prep.outputs.pr }} - name: Get commit sha from PR id: commit-sha uses: actions/github-script@v7 with: script: | const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: process.env.PR }) core.setOutput( 'sha', pr.data.merge_commit_sha ) env: PR: ${{ needs.prep.outputs.pr }} - name: Cherry pick run: | git cherry-pick $SHA -m1 env: SHA: ${{ steps.commit-sha.outputs.sha }} - name: Push cherry pick branch up run: git push origin cherry-pick-$FROZEN_RELEASE_BRANCH/$PR env: FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} PR: ${{ needs.prep.outputs.pr }} - name: Create the PR for cherry pick branch id: cherry-pick-pr uses: actions/github-script@v7 with: script: | const frozenReleaseBranch = process.env.FROZEN_RELEASE_BRANCH; const prNumber = process.env.PR; let cherryPickPRBody = `This PR cherry-picks the following PRs into the frozen release branch: ${frozenReleaseBranch}`; cherryPickPRBody = `${cherryPickPRBody}\n* #${prNumber}\n`; const pr = await github.rest.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, title: `Cherry pick ${prNumber} into frozen release: ${frozenReleaseBranch}`, head: `cherry-pick-${frozenReleaseBranch}/${prNumber}`, base: frozenReleaseBranch, body: cherryPickPRBody }); core.setOutput('cherry-pick-pr', pr.data.html_url); console.log('cherry-pick-pr URL:', pr.data.html_url); // label PR await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.data.number, labels: ["metric: point release request"], }); env: PR: ${{ needs.prep.outputs.pr }} FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} - name: Notify Slack on failure if: ${{ failure() && inputs.skipSlackPing != true }} uses: archive/github-actions-slack@v2.0.0 with: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_CORE_RELESES_DAILY_SLACK_CHANNEL }} slack-text: | :warning-8c: Point release request cherry pick failed for `${{ needs.prep.outputs.release }}` An attempt to cherry pick PR(s) into outgoing `${{ needs.prep.outputs.frozenRelease }}` for `${{ needs.prep.outputs.release }}` has failed. This could be due to a merge conflict or something else that requires manual attention. Please check: https://github.com/woocommerce/woocommerce/pull/${{ needs.prep.outputs.pr }} - name: Notify Slack on success if: ${{ success() && inputs.skipSlackPing != true }} uses: archive/github-actions-slack@v2.0.0 with: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_CORE_RELESES_DAILY_SLACK_CHANNEL }} slack-text: | :info: Point release request cherry pick succeeded for `${{ needs.prep.outputs.release }}` Please merge the following PR :pr: into `${{ needs.prep.outputs.frozenRelease }}`: ${{ steps.cherry-pick-pr.outputs.cherry-pick-pr }} - name: Comment on PR about the failed cherry pick if: ${{ failure() }} run: | gh pr comment $HTML_URL --body "Cherry picking failed for the frozen release: $FROZEN_RELEASE_BRANCH. Please do it manually. Or debug, what happened and run the workflow again. Workflow link for debugging:https://github.com/${{ github.repository_owner }}/${{ github.repository }}/actions/workflows/new-prr-cherry-pick.yml" env: GH_TOKEN: ${{ github.token }} HTML_URL: ${{ github.event.pull_request.html_url }} FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} - name: Comment on PR about the cherry picked PRs to be merged if: ${{ success() }} run: | gh pr comment $HTML_URL --body "Cherry picking was successful for frozen release: $FROZEN_RELEASE_BRANCH. Please merge the following PR: $CHERRY_PICK_PR" env: GH_TOKEN: ${{ github.token }} HTML_URL: ${{ github.event.pull_request.html_url }} FROZEN_RELEASE_BRANCH: ${{ needs.prep.outputs.frozenRelease }} CHERRY_PICK_PR: ${{ steps.cherry-pick-pr.outputs.cherry-pick-pr }}