From 3f554f58bd40474e1ff1bd9041fff5ec6e4bdbaa Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Wed, 15 Dec 2021 17:07:11 +0100 Subject: [PATCH] Detecting breaking changes (#42934) * chore: add a script for detecting breaking changes * chore: add a temporary binary for POC3 * chore: add a Github Action workflow for detecting breaking changes * chore: remove unused variables from the script * chore: rename the POC3 executable script * chore: add a label if there is a breaking change * chore: remove "breaking change" label if all is passing * chore: rename steps * fix: only remove the label if there were no breaking changes * chore: jump to the correct step * chore: skip `@grafana/toolkit` * chore: add a message for opening links in a new tab * chore: update comment message * chore: use Node 16 for the breaking changes workflow * chore: install Yarn separately * chore: use @grafana/levitate * refactor: remove the unused levitate.js bundle * fix: handle error when trying to remove a label that does not exist * chore: delete the comment if there are no breaking changes * chore: add reviewers automatically * fix: use double-quote in shell script * TEMPORARY: introduce a breaking change in `@grafana/data` * fix: use correct line number for the breaking changes * Revert "TEMPORARY: introduce a breaking change in `@grafana/data`" This reverts commit 986ac9ab820b40b8ca943e33ed91fc0695688f43. * chore: remove unnecessary line from .eslintignore --- .github/workflows/detect-breaking-changes.yml | 161 ++++++++++++++++++ scripts/check-breaking-changes.sh | 52 ++++++ 2 files changed, 213 insertions(+) create mode 100644 .github/workflows/detect-breaking-changes.yml create mode 100755 scripts/check-breaking-changes.sh diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml new file mode 100644 index 00000000000..b4f92c57ca5 --- /dev/null +++ b/.github/workflows/detect-breaking-changes.yml @@ -0,0 +1,161 @@ +name: Levitate + +on: push + +jobs: + build: + name: Detecting breaking changes + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install Node.js + uses: actions/setup-node@v2 + with: + node-version: '16' + + - name: Install Yarn + run: npm install --global yarn + + # We need this as we can only access the "Run ID" through the context and we need the "Job ID". + - name: Get link for the Github Action job + id: get-job-link + uses: actions/github-script@v5 + with: + result-encoding: string + script: | + const { owner, repo } = context.repo; + const url = `https://api.github.com/repos/${owner}/${repo}/actions/runs/${context.runId}/jobs` + const result = await github.request(url) + console.log(result.data) + + return `https://github.com/grafana/grafana/runs/${result.data.jobs[0].id}?check_suite_focus=true`; + + - name: Find current pull request ID + uses: jwalton/gh-find-current-pr@v1 + id: finder + + - name: Check if "breaking change" label exists + id: does-label-exist + uses: actions/github-script@v5 + env: + PR_NUMBER: ${{ steps.finder.outputs.pr }} + with: + script: | + const { data } = await github.rest.issues.listLabelsOnIssue({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + }); + const labels = data.map(({ name }) => name); + const doesExist = labels.includes('breaking change'); + + return doesExist ? 1 : 0; + + - name: Debug + run: echo -e "Job link - ${{steps.get-job-link.outputs.result}} \nPull request - ${{steps.finder.outputs.pr}} \nLabel exists - ${{steps.does-label-exist.outputs.result}}" + + - name: Install dependencies + run: yarn install --immutable + + - name: Build packages + run: yarn packages:build + + - name: Detect breaking changes + id: breaking-changes + run: ./scripts/check-breaking-changes.sh + env: + FORCE_COLOR: 3 + GITHUB_JOB_LINK: ${{steps.get-job-link.outputs.result}} + + - name: Comment on PR + if: ${{ steps.breaking-changes.outputs.is_breaking == 1 }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + number: ${{ steps.finder.outputs.pr }} + message: | + ⚠️   **Possible breaking changes** + + _(Open the links below in a new tab to go to the correct steps)_ + + ${{ steps.breaking-changes.outputs.message }} + + [Check console output](${{steps.get-job-link.outputs.result}}) + + - name: Remove comment on PR + if: ${{ steps.breaking-changes.outputs.is_breaking == 0 }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + number: ${{ steps.finder.outputs.pr }} + delete: true + + + - name: Add "breaking change" label + if: ${{ steps.breaking-changes.outputs.is_breaking == 1 && steps.does-label-exist.outputs.result == 0 }} + uses: actions/github-script@v5 + env: + PR_NUMBER: ${{ steps.finder.outputs.pr }} + with: + script: | + github.rest.issues.addLabels({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['breaking change'] + }) + + - name: Remove "breaking change" label + if: ${{ steps.breaking-changes.outputs.is_breaking == 0 && steps.does-label-exist.outputs.result == 1 }} + uses: actions/github-script@v5 + env: + PR_NUMBER: ${{ steps.finder.outputs.pr }} + with: + script: | + github.rest.issues.removeLabel({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + name: 'breaking change' + }) + + # This is very weird, the actual request goes through (comes back with a 201), but does not assign the team. + # Related issue: https://github.com/renovatebot/renovate/issues/1908 + - name: Add "grafana/plugins-platform-frontend" as a reviewer + if: ${{ steps.breaking-changes.outputs.is_breaking == 1 }} + uses: actions/github-script@v5 + env: + PR_NUMBER: ${{ steps.finder.outputs.pr }} + with: + script: | + const response = await github.rest.pulls.requestReviewers({ + pull_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + reviewers: [], + team_reviewers: ['grafana/plugins-platform-frontend'] + }) + + console.log(response) + + - name: Remove "grafana/plugins-platform-frontend" from the list of reviewers + if: ${{ steps.breaking-changes.outputs.is_breaking == 0 }} + uses: actions/github-script@v5 + env: + PR_NUMBER: ${{ steps.finder.outputs.pr }} + with: + script: | + const response = await github.rest.pulls.removeRequestedReviewers({ + pull_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + reviewers: [], + team_reviewers: ['grafana/plugins-platform-frontend'] + }) + + console.log(response) + + - name: Exit + run: exit ${{ steps.breaking-changes.outputs.is_breaking }} + shell: bash + diff --git a/scripts/check-breaking-changes.sh b/scripts/check-breaking-changes.sh new file mode 100755 index 00000000000..a57b763f2f8 --- /dev/null +++ b/scripts/check-breaking-changes.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +PACKAGES=$(lerna list -p -l) +EXIT_CODE=0 +GITHUB_MESSAGE="" + +# Loop through packages +while IFS= read -r line; do + + # Read package info + IFS=':' read -ra ADDR <<< "$line" + PACKAGE_PATH="${ADDR[0]}" + PACKAGE_NAME="${ADDR[1]}" + + # Calculate current and previous package paths / names + PREV="$PACKAGE_NAME@canary" + CURRENT="$PACKAGE_PATH/dist/" + + + # Temporarily skipping @grafana/toolkit, as it doesn't have any exposed static typing + if [[ "$PACKAGE_NAME" == '@grafana/toolkit' ]]; then + continue + fi + + + # Run the comparison and record the exit code + echo "" + echo "" + echo "${PACKAGE_NAME}" + echo "=================================================" + npm exec -- @grafana/levitate compare --prev "$PREV" --current "$CURRENT" + + # Check if the comparison returned with a non-zero exit code + # Record the output, maybe with some additional information + STATUS=$? + + # Final exit code + # (non-zero if any of the packages failed the checks) + if [ $STATUS -gt 0 ] + then + EXIT_CODE=1 + GITHUB_MESSAGE="${GITHUB_MESSAGE}**\`${PACKAGE_NAME}\`** has possible breaking changes ([more info](${GITHUB_JOB_LINK}#step:11:1))
" + fi + +done <<< "$PACKAGES" + +# "Export" the message to an environment variable that can be used across Github Actions steps +echo "::set-output name=is_breaking::$EXIT_CODE" +echo "::set-output name=message::$GITHUB_MESSAGE" + +# We will exit the workflow accordingly at another step +exit 0 \ No newline at end of file