diff --git a/.github/ISSUE_TEMPLATE/new-cfe-template.yml b/.github/ISSUE_TEMPLATE/new-cfe-template.yml index f942012e65d..b7fb74000fd 100644 --- a/.github/ISSUE_TEMPLATE/new-cfe-template.yml +++ b/.github/ISSUE_TEMPLATE/new-cfe-template.yml @@ -17,8 +17,8 @@ body: id: release-number attributes: label: "Which release does this request apply to?" - description: "Format: X.Y" - placeholder: "7.0" + description: "Format: X.Y (Major.Minor)" + placeholder: "9.2" validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/new-prr-template.yml b/.github/ISSUE_TEMPLATE/new-prr-template.yml new file mode 100644 index 00000000000..5f6b8d99ab3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-prr-template.yml @@ -0,0 +1,95 @@ +name: 🚧 Point release request +description: Request handling one or more pull requests(s) as point release request(s). +title: "[PRR]: " +labels: ["point release request"] +body: + - type: markdown + attributes: + value: | + Use this template to request changes to be included as part of a point release. + **The request will be reviewed** and accepted or denied: + + * If accepted, please test your changes in against the release branch and merge. + * If rejected, please change the base against `trunk` and merge it. + + In either case you are responsible for managing the pull request as usual (provide a description, assign reviewers, ensure that CI jobs pass...) + - type: input + id: release-number + attributes: + label: "Which release does this request apply to?" + description: "Format: X.Y (Major.Minor)" + placeholder: "9.2" + validations: + required: true + - type: textarea + id: pr-urls + attributes: + label: "Which PR needs to be included? (please do not enter multiple PRs)" + description: "Pull request URL against the release branch" + placeholder: | + https://github.com/woocommerce/woocommerce/pull/1234 + validations: + required: true + - type: textarea + id: why-needed + attributes: + label: "Why does this PR need a point release?" + placeholder: "This is a revert of ... which introduced a bug that causes ..." + validations: + required: true + - type: textarea + attributes: + id: consequence-if-not-included + label: "What is the consequence if this fix not being included in the point release (if any)? e.g. number of users affected and how they are affected" + placeholder: "The ... flow will be broken for ... users" + validations: + required: true + - type: textarea + id: plan-if-defects-discovered + attributes: + label: "What is the plan should defects to be discovered in these PR after the point release?" + placeholder: "Reverting this PR and ... would be enough" + validations: + required: true + - type: textarea + id: how-to-communicate + attributes: + label: "How should this change be communicated in the release post on the public developer blog: cc @woocommerce/developer-advocacy" + description: "See the blog at [https://developer.woo.com/blog/](https://developer.woo.com/blog/)" + placeholder: "There is no need to add new communication to the already planned one." + validations: + required: true + - type: textarea + id: workaround + attributes: + label: "Is there a workaround to the issue? If yes, how should we communicate it on the (public developer blog)[https://developer.woo.com/blog/]?" + placeholder: "Use the ... flow instead" + validations: + required: true + - type: textarea + id: who-to-ask + attributes: + label: "If you’re not available and we have questions about this request, is there another person(s) and/or a team that we can ping?" + placeholder: "@person or anyone from the ... team" + validations: + required: true + - type: markdown + attributes: + value: | + ## Escape Analysis + For the sake of expediting this request, the details below can be completed at a later time should you so choose. + However, the Escape Analysis section is **required** for any accepted Point Release Request. + In this section: + * Think about how the bug escaped your team. + * Write down ideas on how you could prevent this bug – for example, by writing automated tests, creating a new process, or updating documentation. + * Make a plan with your team to implement the changes proposed above in order to catch the bug earlier next time and add the related tasks to your backlog. + * Please, add a separate comment that includes the details for the Escape Analysis. Together with this Escape Analysis, please make sure to include an actionable item that covers the gap exposed by this analysis. It could be a GitHub issue, the reference of a new item to discuss in a team meeting, etc. Anything that prevents this analysis from getting lost in P2 will be useful. + - type: checkboxes + id: escape-analysis-completed + attributes: + label: "Acknowledgement" + options: + - label: "I understand that I need to write an incident report (aka Escape Analysis) as a comment on this post. This is required for the request to be accepted." + required: true + - label: "I understand that I need to create an issue as a result of the Escape Analysis and reference it in a comment on this post. This can be done at a later time, but it is required for this request to be closed." + required: true diff --git a/.github/workflows/new-cfe-cherry-pick.yml b/.github/workflows/new-cfe-cherry-pick.yml index b7fb42b9e8d..560374a3b85 100644 --- a/.github/workflows/new-cfe-cherry-pick.yml +++ b/.github/workflows/new-cfe-cherry-pick.yml @@ -1,3 +1,4 @@ +# This workflow is used to cherry pick PRs from release branche into trunk. name: New CFE workflow - Cherry pick on: pull_request: @@ -86,7 +87,7 @@ jobs: script: | const event = ${{ toJSON( github.event ) }} - const releaseBranch = '${{ needs.verify.outputs.base_ref }}' + const releaseBranch = process.env.BASE_REF const version = releaseBranch.replace( 'release/', '' ) const pr = event.pull_request.number @@ -98,6 +99,8 @@ jobs: core.setOutput( 'pr', pr ) core.setOutput( 'version', version ) core.setOutput( 'release', releaseBranch ) + env: + BASE_REF: ${{ needs.verify.outputs.base_ref }} check-release-branch-exists: name: Check for existence of release branch @@ -113,8 +116,11 @@ jobs: await github.request( 'GET /repos/{owner}/{repo}/branches/{branch}', { owner: context.repo.owner, repo: context.repo.repo, - branch: '${{ needs.prep.outputs.release }}', + branch: process.env.RELEASE_BRANCH, } ); + env: + RELEASE_BRANCH: ${{ needs.prep.outputs.release }} + cherry-pick-run: name: Run cherry pick tool runs-on: ubuntu-20.04 @@ -137,7 +143,10 @@ jobs: run: git checkout trunk - name: Create a cherry pick branch based on trunk branch - run: git checkout -b cherry-pick-${{ needs.prep.outputs.version }}/${{ needs.prep.outputs.pr }} + run: git checkout -b cherry-pick-$RELEASE_BRANCH/$PR + env: + RELEASE_BRANCH: ${{ needs.prep.outputs.release }} + PR: ${{ needs.prep.outputs.pr }} - name: Get commit sha from PR id: commit-sha @@ -147,32 +156,42 @@ jobs: const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: '${{ needs.prep.outputs.pr }}' + 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 ${{ steps.commit-sha.outputs.sha }} -m1 + git cherry-pick $SHA -m1 + env: + SHA: ${{ steps.commit-sha.outputs.sha }} - name: Push cherry pick branch up - run: git push origin cherry-pick-${{ needs.prep.outputs.version }}/${{ needs.prep.outputs.pr }} + run: git push origin cherry-pick-$RELEASE_BRANCH/$PR + env: + RELEASE_BRANCH: ${{ needs.prep.outputs.release }} + 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 prNumber = process.env.PR; + const releaseBranch = process.env.RELEASE_BRANCH; + let cherryPickPRBody = "This PR cherry-picks the following PRs into the trunk branch:\n"; - cherryPickPRBody = `${cherryPickPRBody}` + `* #${{ needs.prep.outputs.pr }}` + "\n"; + cherryPickPRBody = `${cherryPickPRBody}` + `* #${prNumber}` + "\n"; const pr = await github.rest.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, - title: "Cherry pick ${{ needs.prep.outputs.pr }} into trunk", - head: "cherry-pick-${{ needs.prep.outputs.version }}/${{ needs.prep.outputs.pr }}", + title: `Cherry pick ${prNumber} into trunk`, + head: `cherry-pick-${releaseBranch}/${prNumber}`, base: "trunk", body: cherryPickPRBody }) @@ -188,6 +207,9 @@ jobs: issue_number: pr.data.number, labels: ["metric: code freeze exception"], }); + env: + PR: ${{ needs.prep.outputs.pr }} + RELEASE_BRANCH: ${{ needs.prep.outputs.release }} - name: Notify Slack on failure if: ${{ failure() && inputs.skipSlackPing != true }} @@ -198,7 +220,7 @@ jobs: slack-text: | :warning-8c: CFE cherry pick failed for '${{ needs.prep.outputs.release }}' - An attempt to cherry pick PR(s) into outgoing trunk 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 }} + An attempt to cherry pick PR(s) into outgoing trunk 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 }} @@ -207,8 +229,25 @@ jobs: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_CORE_RELESES_DAILY_SLACK_CHANNEL }} slack-text: | - :info: CFE cherry pick succeeded for '${{ needs.prep.outputs.release }}' + :info: CFE cherry pick succeeded for `${{ needs.prep.outputs.release }}` - Please merge the following PR :pr: into trunk: + Please merge the following PR :pr: into `trunk`: ${{ 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 trunk. 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-cfe-cherry-pick.yml" + env: + GH_TOKEN: ${{ github.token }} + HTML_URL: ${{ github.event.pull_request.html_url }} + + - 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 trunk. Please merge the following PR: $CHERRY_PICK_PR" + env: + GH_TOKEN: ${{ github.token }} + HTML_URL: ${{ github.event.pull_request.html_url }} + CHERRY_PICK_PR: ${{ steps.cherry-pick-pr.outputs.cherry-pick-pr }} diff --git a/.github/workflows/new-cfe-pre-build-compile-changelog-file.yml b/.github/workflows/new-cfe-pre-build-compile-changelog-file.yml index 0aefbf6e0a3..54af6d1a186 100644 --- a/.github/workflows/new-cfe-pre-build-compile-changelog-file.yml +++ b/.github/workflows/new-cfe-pre-build-compile-changelog-file.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: inputs: version: - description: 'Version override. Default version is fetched from monthly release calendar, you can override the version but make sure the that the branch release/{version} exists on remote.' + description: 'Version override. Default version is fetched from the base branch name, you can override the version but make sure the that the branch release/{version} exists on remote. Format: X.Y (Major.Minor)' required: false default: '' @@ -21,6 +21,37 @@ jobs: contents: write pull-requests: write steps: + - name: Get version from the branch name workflow is running on + if: ${{ github.event.inputs.version == '' }} + uses: actions/github-script@v7 + id: extract-version + with: + script: | + const refName = process.env.GITHUB_REF_NAME; + const versionMatch = refName.match(/^release\/(\d+\.\d+)$/); + if (versionMatch) { + const version = versionMatch[1]; + console.log(`Extracted version: ${version}`); + core.setOutput('version', version); + } else { + core.setFailed(`Branch name ${refName} does not match the expected pattern 'release/x.y'`); + process.exit(1); + } + + - name: Validate version input override + if: ${{ github.event.inputs.version != '' }} + uses: actions/github-script@v7 + env: + VERSION: ${{ github.event.inputs.version }} + with: + script: | + const version = process.env.VERSION; + if (!/^\d+\.\d+$/.test(version)) { + core.setFailed('Invalid version format. The version must be in the format X.Y'); + core.info(`Version you entered: ${version}`); + process.exit(1); + } + - name: Checkout code uses: actions/checkout@v3 with: @@ -43,13 +74,8 @@ jobs: pnpm build working-directory: tools/monorepo-utils - - name: 'Get the versions for the accelerated and monthly releases' - id: get-versions - if: ${{ github.event.inputs.version == '' }} - run: pnpm utils code-freeze get-version - - name: Generate changelog changes and create PR id: changelog env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: pnpm utils code-freeze changelog -o ${{ github.repository_owner }} -v ${{ github.event.inputs.version || steps.get-versions.outputs.monthlyVersionXY }} + run: pnpm utils code-freeze changelog -o ${{ github.repository_owner }} -v ${{ github.event.inputs.version || steps.extract-version.outputs.version }} diff --git a/.github/workflows/new-cfe-notifications.yml b/.github/workflows/new-cfe-prr-notifications.yml similarity index 59% rename from .github/workflows/new-cfe-notifications.yml rename to .github/workflows/new-cfe-prr-notifications.yml index d4aa1ad2f40..75fbe57de3e 100644 --- a/.github/workflows/new-cfe-notifications.yml +++ b/.github/workflows/new-cfe-prr-notifications.yml @@ -1,4 +1,4 @@ -name: New CFE workflow notifications +name: New CFE/PRR workflow notifications on: issues: types: [labeled] @@ -7,7 +7,7 @@ permissions: {} jobs: prep: - if: github.event.label.name == 'CFE Approved' || github.event.label.name == 'CFE Rejected' + if: github.event.label.name == 'Approved' || github.event.label.name == 'Rejected' runs-on: ubuntu-20.04 outputs: release_number: ${{ steps.extract-release.outputs.RELEASE_NUMBER }} @@ -38,24 +38,44 @@ jobs: } cfe-created: - if: github.event.label.name == 'code freeze exception' + if: github.event.label.name == 'code freeze exception' || github.event.label.name == 'point release request' runs-on: ubuntu-20.04 steps: + - name: Set Slack Message + id: set-message + uses: actions/github-script@v7 + with: + script: | + const event = context.payload; + const labelName = event.label?.name; + const issueTitle = event.issue.title; + const issueUrl = event.issue.html_url; + + let message = ''; + + // Determine the type of message based on the label name + if (labelName === 'code freeze exception') { + message = `:arrow_right: New CFE request: ${issueTitle} ${issueUrl}`; + } else { + message = `:arrow_right: New PRR request: ${issueTitle} ${issueUrl}`; + } + + // Set the message as a core output + core.setOutput('SLACK_MESSAGE', message); + - name: Notify Slack uses: archive/github-actions-slack@v2.0.0 id: notify with: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_RELEASE_SLACK_CHANNEL }} - slack-text: | - :arrow_right: New CFE request: ${{ github.event.issue.title }} - ${{ github.event.issue.html_url }} + slack-text: ${{ steps.set-message.outputs.SLACK_MESSAGE }} slack-optional-unfurl_links: false slack-optional-unfurl_media: false continue-on-error: true - cfe-approved: - if: github.event.label.name == 'CFE Approved' + request-approved: + if: ${{ github.event.label.name == 'Approved' }} runs-on: ubuntu-20.04 needs: - prep @@ -95,7 +115,17 @@ jobs: PR_NUMBER: ${{ steps.extract-pr.outputs.PR_NUMBER }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh pr edit "$PR_NUMBER" --add-label "cherry pick to trunk" --repo "$OWNER/$REPO" + gh pr edit $PR_NUMBER --add-label "cherry pick to trunk" --repo "$OWNER/$REPO" + + - name: Add label 'cherry pick to frozen release' to PR + if: contains(github.event.issue.labels.*.name, 'point release request') + env: + OWNER: ${{ github.event.repository.owner.login }} + REPO: ${{ github.event.repository.name }} + PR_NUMBER: ${{ steps.extract-pr.outputs.PR_NUMBER }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr edit $PR_NUMBER --add-label "cherry pick to frozen release" --repo "$OWNER/$REPO" - name: Apply Milestone to the Issue env: @@ -113,21 +143,39 @@ jobs: run: | gh issue comment "$ISSUE_URL" --body "This request has been approved. Please merge the PR to release branch." + - name: Set Slack Message + id: set-message + uses: actions/github-script@v7 + with: + script: | + const event = context.payload; // Accessing the event directly from the context + const labelName = event.label?.name; + const issueTitle = event.issue.title; + const issueUrl = event.issue.html_url; + + let message = ''; + + if (labelName === 'code freeze exception') { + message = `:white_check_mark: CFE request approved: ${issueTitle} ${issueUrl}`; + } else { + message = `:white_check_mark: PRR request approved: ${issueTitle} ${issueUrl}`; + } + + core.setOutput('SLACK_MESSAGE', message); + - name: Notify Slack uses: archive/github-actions-slack@v2.0.0 id: notify with: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_CORE_RELESES_DAILY_SLACK_CHANNEL }} - slack-text: | - :white_check_mark: CFE request approved: ${{ github.event.issue.title }} - ${{ github.event.issue.html_url }} + slack-text: ${{ steps.set-message.outputs.SLACK_MESSAGE }} slack-optional-unfurl_links: false slack-optional-unfurl_media: false continue-on-error: true - cfe-rejected: - if: github.event.label.name == 'CFE Rejected' + request-rejected: + if: ${{ github.event.label.name == 'Rejected' }} runs-on: ubuntu-20.04 needs: - prep @@ -143,12 +191,33 @@ jobs: echo "Applying milestone: $MILESTONE" gh issue edit "$ISSUE_URL" --milestone "$MILESTONE" - - name: Close CFE Issue + - name: Close the request env: ISSUE_URL: ${{ github.event.issue.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh issue close --comment "Closing issue as CFE is rejected - $ISSUE_URL. Please switch the base to trunk and merge." "$ISSUE_URL" + gh issue close "$ISSUE_URL" --comment "Closing issue the request is rejected - $ISSUE_URL. Please switch the base to trunk and merge." + + - name: Set Slack Message + id: set-message + uses: actions/github-script@v7 + with: + script: | + const event = context.payload; + const labelName = event.label?.name; + const issueTitle = event.issue.title; + const issueUrl = event.issue.html_url; + + let message = ''; + + if (labelName === 'code freeze exception') { + message = `:x: CFE request rejected: ${issueTitle} ${issueUrl}`; + } else { + message = `:x: PRR request rejected: ${issueTitle} ${issueUrl}`; + } + + core.setOutput('SLACK_MESSAGE', message); + - name: Notify Slack uses: archive/github-actions-slack@v2.0.0 @@ -156,9 +225,7 @@ jobs: with: slack-bot-user-oauth-access-token: ${{ secrets.CODE_FREEZE_BOT_TOKEN }} slack-channel: ${{ secrets.WOO_CORE_RELESES_DAILY_SLACK_CHANNEL }} - slack-text: | - :x: CFE request rejected: ${{ github.event.issue.title }} - ${{ github.event.issue.html_url }} + slack-text: ${{ steps.set-message.outputs.SLACK_MESSAGE }} slack-optional-unfurl_links: false slack-optional-unfurl_media: false continue-on-error: true diff --git a/.github/workflows/new-prr-cherry-pick.yml b/.github/workflows/new-prr-cherry-pick.yml new file mode 100644 index 00000000000..515b44f77a9 --- /dev/null +++ b/.github/workflows/new-prr-cherry-pick.yml @@ -0,0 +1,295 @@ +# 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 }} diff --git a/plugins/woocommerce/changelog/prr-flow b/plugins/woocommerce/changelog/prr-flow new file mode 100644 index 00000000000..2106fd74e43 --- /dev/null +++ b/plugins/woocommerce/changelog/prr-flow @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Point release request flow for development use.