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, }, ], }