From 0cd9ce6ca3006efbd542ccf4af4635512a4707dc Mon Sep 17 00:00:00 2001 From: John White <750350+johnhwhite@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:22:50 -0400 Subject: [PATCH] ci: add cherry-pick to main (#72) --- .github/workflows/cherry-pick.yml | 160 ++++++++++++++++++++++++++++++ nx.json | 3 + 2 files changed, 163 insertions(+) create mode 100644 .github/workflows/cherry-pick.yml diff --git a/.github/workflows/cherry-pick.yml b/.github/workflows/cherry-pick.yml new file mode 100644 index 00000000..4039456b --- /dev/null +++ b/.github/workflows/cherry-pick.yml @@ -0,0 +1,160 @@ +name: Cherry pick +on: + pull_request: + types: + - closed + branches: + - 8.x.x + +env: + TARGET_BRANCH: main + FROM_BRANCH: ${{ github.event.pull_request.base.ref }} + +jobs: + cherry-pick: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ env.TARGET_BRANCH }} + fetch-depth: 0 + token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + + - uses: actions/setup-node@v3 + id: setup-node + with: + node-version-file: '.nvmrc' + + - name: Cache node modules + id: cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ steps.setup-node.outputs.node-version }}-modules-${{ hashFiles('package-lock.json') }} + + - name: npm install + if: steps.cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Cherry pick + run: | + git config user.name 'Blackbaud Sky Build User' + git config user.email 'sky-build-user@blackbaud.com' + + # Echo commands to the log. + set -x + + # Do not exit on error. + set +e + + # Cherry-pick the merge commit into the target branch, which is checked out. + npx skyux-dev cherry-pick \ + --baseBranch=${{ env.TARGET_BRANCH }} \ + --hash=${{ github.event.pull_request.merge_commit_sha }} \ + --skip-confirmation + + if [ $? -ne 0 ]; then + echo "CHERRY_PICK_RESULT=failed" >> $GITHUB_ENV + exit 0 + fi + + # Get the name of the cherry-pick branch. + CHERRY_PICK_BRANCH=$(git branch --show-current) + # Add the cherry-pick branch to the environment. + echo "CHERRY_PICK_BRANCH=${CHERRY_PICK_BRANCH}" >> $GITHUB_ENV + + # Push the cherry-pick to a new cherry-pick branch. + git push -u origin ${CHERRY_PICK_BRANCH} + + if [ $? -ne 0 ]; then + echo "CHERRY_PICK_RESULT=failed" >> $GITHUB_ENV + exit 0 + fi + env: + GH_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + + - uses: actions/github-script@v6 + if: ${{ env.CHERRY_PICK_RESULT != 'failed' }} + with: + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + script: | + const pr = context.payload.pull_request; + let body = `:cherries: Cherry picked from #${pr.number} [${pr.title}](${pr.html_url})` + const prAzureBoardLink = pr.body?.match(/(?<=\[)AB#\d+(?=])/g); + if (prAzureBoardLink) { + body += `\n\n${prAzureBoardLink.join(' \n')} `; + } + github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: process.env.CHERRY_PICK_BRANCH, + base: process.env.TARGET_BRANCH, + title: `${pr.title} (#${pr.number})`, + body + }).then(result => { + console.log(`Created PR #${result.data.number}: ${result.data.html_url}`); + core.exportVariable('PR_URL', result.data.html_url); + core.exportVariable('CHERRY_PICK_RESULT', 'success'); + const riskLabels = pr.labels.map(label => label.name).filter(label => label.startsWith('risk level')); + if (riskLabels.length === 0) { + if (pr.labels.find(label => label.name.startsWith('autorelease'))) { + // Changelog PR, so add minimal risk level labels. + riskLabels.push('risk level (author): 1', 'risk level (reviewer): 1'); + } else { + // No risk level label found, so don't add any. + return; + } + } + return github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: result.data.number, + labels: riskLabels + }); + }).catch(error => { + console.log(error); + core.warning(`Failed to create PR: ${error.message}`); + core.exportVariable('CHERRY_PICK_RESULT', 'failed'); + }); + + - name: Comment on the original PR when cherry-pick is successful + if: ${{ env.CHERRY_PICK_RESULT == 'success' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Cherry-pick successful! :cherries: :tada: See ${{ env.PR_URL }}' + }) + + - name: Comment on the original PR when cherry-pick fails + if: ${{ env.CHERRY_PICK_RESULT != 'success' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Cherry-pick [failed](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})! :x: Please resolve conflicts and create a new PR.' + }) + + - name: Notify Slack when cherry-pick fails + if: ${{ env.CHERRY_PICK_RESULT != 'success' }} + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_TITLE: ':cherries: :x: Cherry-pick failed for “${{ github.event.pull_request.title }} (#${{ github.event.pull_request.number}})”' + SLACK_MESSAGE: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}' + SLACK_ICON_EMOJI: ':github:' + SLACK_USERNAME: GitHub + #cor-skyux-notifications + SLACK_CHANNEL: C01GY7ZP4HM + SLACK_COLOR: 'fail' + SLACK_FOOTER: 'Blackbaud Sky Build User' + MSG_MINIMAL: 'true' diff --git a/nx.json b/nx.json index 55bb9030..39adf885 100644 --- a/nx.json +++ b/nx.json @@ -1,6 +1,9 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", "npmScope": "stache", + "affected": { + "defaultBase": "main" + }, "tasksRunnerOptions": { "default": { "runner": "@nrwl/nx-cloud",