From f23bfafe4be3dde6d41fdf9f5a0fcb377abb7f13 Mon Sep 17 00:00:00 2001 From: Philippe Serhal Date: Tue, 28 May 2024 13:25:01 -0400 Subject: [PATCH] chore: create Issue when Angular bump fails Configure Renovate to create PRs bumping Angular packages in test fixtures, and add a CI workflow to automatically create an Issue when one of these PRs fails. Separately, we'll configure an integration from GitHub Issues to our triage inbox. This allows us to find out proactively when new or upcoming releases may cause regressions, before users are affected. See https://github.com/netlify/remix-compute/pull/355 and https://github.com/netlify/remix-compute/pull/365. --- .github/workflows/failure-notifier.yml | 103 +++++++++++++++++++++++++ renovate.json5 | 35 ++++++--- 2 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/failure-notifier.yml diff --git a/.github/workflows/failure-notifier.yml b/.github/workflows/failure-notifier.yml new file mode 100644 index 00000000..bb82117a --- /dev/null +++ b/.github/workflows/failure-notifier.yml @@ -0,0 +1,103 @@ +# We've configured Renovate to open bump PRs for Angular dependencies within our +# test fixtures. This workflow sends notifications when one of these PRs fails. + +name: Notify on Angular bump failures + +on: + pull_request: + types: [opened, synchronize, labeled, unlabeled] +jobs: + waitForWorkflows: + name: Wait for workflows + runs-on: ubuntu-latest + if: always() + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Wait for workflows + id: wait + uses: smartcontractkit/chainlink-github-actions/utils/wait-for-workflows@b49a9d04744b0237908831730f8553f26d73a94b + with: + max-timeout: '900' + polling-interval: '30' + github-token: ${{ secrets.GITHUB_TOKEN }} + notify-on-failure: + name: Notify on failure + needs: [waitForWorkflows] + # Note that this doesn't imply success of the workflows themselves, just the waiting. + if: needs.waitForWorkflows.result == 'success' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Check out the repository + uses: actions/checkout@v4 + - name: Check conditions for failure notification + id: check_label + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const sha = context.payload.pull_request.head.sha; + const prNumber = context.payload.pull_request.number; + + // Get PR status, which is now settled + const { data: {check_suites: checkSuites} } = await github.rest.checks.listSuitesForRef({ + owner, + repo, + ref: sha + }); + + // Get current PR state and labels + const { data: pullRequest } = await github.rest.pulls.get({ + owner, + repo, + pull_number: prNumber, + // Don't filter on `state` here so we can gracefuly handle an "expected" race + // condition (PR closed between trigger and query) but still throw on unexpected errors. + }); + if (pullRequest == null) { + core.setFailed("Aborting - cannot find PR corresponding to event trigger"); + return; + } + + const prIsOpen = pullRequest.state === "open"; + // NOTE: Technically, we should query both Check Suites and Commit Statuses. + // We're assuming here that this repo exclusively uses the Checks API. + const prDidFail = checkSuites.some(({conclusion}) => + conclusion === "failure" || conclusion === "timed_out" + ); + // See `renovate.json5` at project root. + const REQUIRED_LABEL = "bump-framework-in-fixtures"; + const prHasRequiredLabel = pullRequest.labels.some(label => label.name === REQUIRED_LABEL); + const shouldSendNotification = prIsOpen && prDidFail && prHasRequiredLabel; + core.setOutput("should_send_notif", shouldSendNotification ? "true" : "false"); + - name: Create issue on failure + if: ${{ steps.check_label.outputs.should_send_notif == 'true' }} + uses: actions/github-script@v7 + with: + script: | + const ISSUE_LABEL = "framework-bump-failure"; + const { owner, repo } = context.repo; + const {data: issues} = await github.rest.issues.listForRepo({ + owner, + repo, + state: "open", + labels: [ISSUE_LABEL] + }); + if (issues.length > 0) { + console.log(`Open issue already exists: ${issues[0].html_url}`); + return; + } + const prUrl = context.payload.pull_request.html_url; + const {data: issue} = await github.rest.issues.create({ + owner, + repo, + title: "Possible regression with new framework release", + labels: [ISSUE_LABEL], + body: `A framework release bump in test fixtures has failed. Check ${prUrl}.` + }); + console.log(`Created issue: ${issue.html_url}`); diff --git a/renovate.json5 b/renovate.json5 index f0a89d25..44207d26 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -1,18 +1,35 @@ { + $schema: 'https://docs.renovatebot.com/renovate-schema.json', extends: ['github>netlify/renovate-config:default'], ignorePresets: [':prHourlyLimit2'], semanticCommits: true, - dependencyDashboard: true, - automerge: true, + // The config we're extending ignores test dirs, but we want to bump some fixture deps + ignorePaths: ['**/node_modules/**'], packageRules: [ + // Since we've enabled Renovate (see above) for fixture sites, adjust the config for these. { - packageNames: [ - // Those cannot be upgraded to requiring ES modules - 'strip-ansi', - ], - major: { - enabled: false, - }, + matchFileNames: ['tests/**/fixtures/**/package.json'], + // If a fixture requires a specific framework version, never bump it. + updatePinnedDependencies: false, + // Always use `chore:` (since these are test fixtures), to avoid no-op releases. + extends: [':semanticCommitTypeAll(chore)'], + }, + { + description: 'Stable & unstable Angular bumps in test fixtures', + matchFileNames: ['tests/**/fixtures/**/package.json'], + // See https://docs.renovatebot.com/presets-monorepo/#monorepoangular. + matchSourceUrls: ['https://github.com/angular/angular'], + // Override the schedule to get immediate PRs. + schedule: null, + // Apply a unique label so we can trigger additional workflows for these PRs. + addLabels: ['bump-framework-in-fixtures'], + // Bump even if the release isn't tagged as `latest`. + respectLatest: false, + // Bump even if it's a pre-release (e.g. 1.2.3-beta.8). + ignoreUnstable: false, + // Ideally we'd like to disable automerge only for unstable bumps, but this is + // difficult (or impossible) to implement so we just disable it entirely. + automerge: false, }, ], }