diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..4b2487c597e --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,26 @@ +name: 'Stale PR Bot' +on: + schedule: + - cron: '0 4 * * *' + +permissions: + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + with: + days-before-issue-stale: -1 # disabled for issues + + days-before-pr-stale: 90 # 3 months + days-before-pr-close: 14 # 2 weeks + stale-pr-label: "stale" + exempt-pr-labels: "keep-open" + exempt-draft-pr: true + stale-pr-message: | + This pull request has been marked as stale due to 90 days of inactivity. + If this is still relevant, please update or comment to keep it open. + If this should be kept open indefinitely, please apply the label `keep-open`. + Otherwise, it will be automatically closed after 14 days. diff --git a/scripts/verify-ci-config.js b/scripts/verify-ci-config.js index becc7287487..25b642ed8cd 100644 --- a/scripts/verify-ci-config.js +++ b/scripts/verify-ci-config.js @@ -159,9 +159,31 @@ checkPlugins(path.join(__dirname, '..', '.github', 'workflows', 'appsec.yml')) /// / Verifying that tests run on correct triggers /// / +const IGNORED_WORKFLOWS = { + all: [ + 'prepare-release-proposal.yml', + 'rebase-release-proposal.yml', + 'release-3.yml', + 'release-4.yml', + 'release-dev.yml', + 'release-latest.yml', + 'release-proposal.yml', + 'codeql-analysis.yml', + 'pr-labels.yml' + ], + trigger_pull_request: [ + 'stale.yml' + ], + trigger_push: [ + 'package-size.yml', + 'stale.yml' + ], + trigger_schedule: [] +} + const workflows = fs.readdirSync(path.join(__dirname, '..', '.github', 'workflows')) .filter(file => - !['release', 'codeql', 'pr-labels'] + !IGNORED_WORKFLOWS.all .reduce((contained, name) => contained || file.includes(name), false) ) @@ -173,13 +195,16 @@ for (const workflow of workflows) { const yamlPath = path.join(__dirname, '..', '.github', 'workflows', workflow) const yamlContent = yaml.parse(fs.readFileSync(yamlPath, 'utf8')) const triggers = yamlContent.on - if (triggers?.pull_request !== null) { + if (!IGNORED_WORKFLOWS.trigger_pull_request.includes(workflow) && + triggers?.pull_request !== null) { triggersError(workflow, 'The `pull_request` trigger should be blank') } - if (workflow !== 'package-size.yml' && triggers?.push?.branches?.[0] !== 'master') { + if (!IGNORED_WORKFLOWS.trigger_push.includes(workflow) && + triggers?.push?.branches?.[0] !== 'master') { triggersError(workflow, 'The `push` trigger should run on master') } - if (triggers?.schedule?.[0]?.cron !== '0 4 * * *') { + if (!IGNORED_WORKFLOWS.trigger_schedule.includes(workflow) && + triggers?.schedule?.[0]?.cron !== '0 4 * * *') { triggersError(workflow, 'The `cron` trigger should be \'0 4 * * *\'') } }