From fa6af0e2e265738d5f023088c7e108a39f3367bd Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Fri, 11 Sep 2026 22:21:11 -0400 Subject: [PATCH] chore: remove new-pr label and 24 hour rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the `new-pr 🌱` label and everything that existed to manage it (24 hour rule handler, its cron, exclusion lists, tests, fixtures, README section). API review used that label as its minimum open time gate, so that gate is now time based instead. `checkPRReadyForMerge` compares against the same ready time the check title already shows ("ready on "): opened / last marked ready for review + 7 days. Things that behave differently: * `api-review/skip-delay ⏰` now actually skips the delay. Previously it only changed the date in the check title and the real bypass was `fast-track` / `backport` removing `new-pr`. * The 5 minute cron lives in `setupAPIReviewStateManagement` now and only looks at open PRs that have an `api-review/*` label. * The old cron paginated from `page = 0` which GitHub treats as page 1, so the first 100 PRs were processed twice per run. Switched to `octokit.paginate`. The `new-pr 🌱` label itself will need deleting from electron/electron by hand after this deploys. --- README.md | 18 +- spec/24-hour-rule.spec.ts | 288 ------------------ spec/api-review-state.spec.ts | 102 ++++++- .../pull_request.new-pr_label.json | 108 ------- .../pull_request.no_review_label.json | 2 + .../pr-open-time/pull_request.opened.json | 184 ----------- .../pull_request.semver-major.json | 77 ----- .../pull_request.semver-minor.json | 77 ----- .../pull_request.semver-missing.json | 67 ---- .../pull_request.semver-none.json | 77 ----- .../pull_request.semver-patch.json | 77 ----- .../pull_request.should_label.json | 77 ----- .../pull_request.should_not_label.json | 67 ---- .../pull_request.labeled.json | 9 - src/24-hour-rule.ts | 199 ------------ src/api-review-state.ts | 102 ++++++- src/constants.ts | 5 - src/index.ts | 2 - src/types.ts | 2 - 19 files changed, 193 insertions(+), 1347 deletions(-) delete mode 100644 spec/24-hour-rule.spec.ts delete mode 100644 spec/fixtures/api-review-state/pull_request.new-pr_label.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.opened.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.semver-major.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.semver-minor.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.semver-missing.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.semver-none.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.semver-patch.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.should_label.json delete mode 100644 spec/fixtures/pr-open-time/pull_request.should_not_label.json delete mode 100644 src/24-hour-rule.ts diff --git a/README.md b/README.md index dfdc839..980899c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Test](https://github.com/electron/cation/actions/workflows/test.yml/badge.svg)](https://github.com/electron/cation/actions/workflows/test.yml) -`cation` is Electron's PR monitoring bot, which serves four primary functions - semver label enforcement, PR open time enforcement, API review bookkeeping, and deprecation review. Each of the four are discussed in further detail below. +`cation` is Electron's PR monitoring bot, which serves three primary functions - semver label enforcement, API review bookkeeping, and deprecation review. Each of the three are discussed in further detail below. ## Semver Label @@ -16,18 +16,6 @@ This bot is responsible for ensuring that all open PRs to Electron are labeled w Screen Shot 2020-12-16 at 9 15 48 AM -## PR Open Time - -The bot is also responsible for ensuring that any given PR is open for an amount of time that reflects its impact on user-facing code. This is also done to ensure that all potential stakeholders for that PR are given ample time to review it and discuss API ergonomics amongst ways it may affect users. - -Timespans: -* `semver/major` - 168 hours (7 days) -* `semver/minor` - 168 hours (7 days) -* `semver/patch` - 24 hours (1 day) -* `semver/none` - 24 hours (1 days), but in some cases (depending on the PR and its goals) there is no minimum time. - -Backport PRs (PRs to a release branch that is not `main`) do not require a minimum time, and a `fast-track` label may be optionally applied to a PR to indicate that it is intended to bypass the expected minimum time if sufficient reason exists to do so. - ## API Review The bot controls the API review lifecycle on behalf of the [API Working Group](https://github.com/electron/governance/tree/main/wg-api). @@ -38,7 +26,7 @@ This group's review is mandated on all API changes, and their goal is twofold: Even changes that seem trivial can often be made more consistent and future-proof with some modifications, and the folks on the API WG have the expertise to spot and suggest those changes. -In accordance with the above goals, this bot performs several bookkeeping duties. When a new PR is opened which is either `semver/minor` or `semver/major`, it will automatically add an `api-review/requested 🗳` label to the PR. To add clarity to whether a review is occurring in a given Electron governance member's capacity as a member of the API WG, this bot then adds a GitHub Check on the PR which will update as members of the API WG indicate their approval statuses. +In accordance with the above goals, this bot performs several bookkeeping duties. When a new PR is opened which is either `semver/minor` or `semver/major`, it will automatically add an `api-review/requested 🗳` label to the PR. Backport PRs (PRs to a release branch that is not `main`) and PRs labeled `backport`, `backport-check-skip`, or `fast-track 🚅` are exempt from API review. To add clarity to whether a review is occurring in a given Electron governance member's capacity as a member of the API WG, this bot then adds a GitHub Check on the PR which will update as members of the API WG indicate their approval statuses. Members of the API Working Group must indicate their approval by leaving a comment via a PR Review containing `API LGTM`. This may not necessarily be a full approval with the GitHub API since approval by the API is primarily about the API shape and design. Both a PR review that comments and includes an LGTM indication or which is an approval with LGTM are sufficient. @@ -46,6 +34,8 @@ Members of the API Working Group must indicate their approval by leaving a comme Screen Shot 2021-11-02 at 10 49 27 AM +PRs undergoing API review must be open for a minimum of 168 hours (7 days), to ensure that all potential stakeholders for that PR are given ample time to review it and discuss API ergonomics amongst ways it may affect users. If the PR was previously a draft, this time is counted from when it was most recently marked ready for review. + If a PR has passed its minimum open time and has the requisite number of approvals with no outstanding requests for changes, the bot will then switch `api-review/requested 🗳` to `api-review/approved ✅`, and the PR is free to be merged. If outstanding change requests persist, then the group will initiate consensus-seeking procedures and ultimately choose to approve or decline the PR. If the decision is made to decline, the API WG chair will then comment on the PR with `API Declined` and the bot will update `api-review/requested 🗳` to `api-review/declined ❌`. For PRs that need to land faster than the minimum open time (e.g. to respond to OS or Chromium updates), the minimum open time can be bypassed by adding a `api-review/skip-delay ⏰` label to the PR. This label may be added to a PR if at least two members of the API WG representing two different employers approve fast-tracking the PR. diff --git a/spec/24-hour-rule.spec.ts b/spec/24-hour-rule.spec.ts deleted file mode 100644 index 755654c..0000000 --- a/spec/24-hour-rule.spec.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { Probot, ProbotOctokit } from 'probot'; -import nock from 'nock'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; - -import { - setUp24HourRule, - getMinimumOpenTime, - shouldPRHaveLabel, - labelShouldBeChecked, -} from '../src/24-hour-rule'; -import { - BACKPORT_LABEL, - BACKPORT_SKIP_LABEL, - FAST_TRACK_LABEL, - MINIMUM_MAJOR_OPEN_TIME, - MINIMUM_MINOR_OPEN_TIME, - MINIMUM_PATCH_OPEN_TIME, - NEW_PR_LABEL, - SEMVER_LABELS, - SEMVER_NONE_LABEL, -} from '../src/constants'; -import { loadFixture } from './utils'; - -const GH_API = 'https://api.github.com'; - -const handler = async (app: Probot) => { - setUp24HourRule(app, true); -}; - -describe('pr open time', () => { - let robot: Probot; - let moctokit: any; - - beforeEach(() => { - nock.cleanAll(); - nock.disableNetConnect(); - - robot = new Probot({ - githubToken: 'test', - Octokit: ProbotOctokit.defaults({ - retry: { enabled: false }, - throttle: { enabled: false }, - }), - }); - - moctokit = { - rest: { - issues: { - listEventsForTimeline: vi.fn().mockReturnValue({ data: [] }), - }, - }, - } as any as ProbotOctokit; - - robot.load(handler); - }); - - afterEach(() => { - if (!nock.isDone()) { - // Output pending mocks to aid debugging when test fails. - // eslint-disable-next-line no-console - console.log('Pending nock mocks:', nock.pendingMocks()); - } - expect(nock.isDone()).toEqual(true); - nock.cleanAll(); - }); - - it('correctly returns the time for a semver-patch label', async () => { - const payload = loadFixture('pr-open-time/pull_request.semver-patch.json'); - const minTime = getMinimumOpenTime(payload); - - expect(minTime).toEqual(MINIMUM_PATCH_OPEN_TIME); - }); - - it('correctly returns the time for a semver-minor label', async () => { - const payload = loadFixture('pr-open-time/pull_request.semver-minor.json'); - const minTime = getMinimumOpenTime(payload); - - expect(minTime).toEqual(MINIMUM_MINOR_OPEN_TIME); - }); - - it('correctly returns the time for a semver-major label', async () => { - const payload = loadFixture('pr-open-time/pull_request.semver-major.json'); - const minTime = getMinimumOpenTime(payload); - - expect(minTime).toEqual(MINIMUM_MAJOR_OPEN_TIME); - }); - - it('correctly returns the time for a semver-none label', async () => { - const payload = loadFixture('pr-open-time/pull_request.semver-none.json'); - const minTime = getMinimumOpenTime(payload); - - expect(minTime).toEqual(MINIMUM_PATCH_OPEN_TIME); - }); - - it('correctly returns the time for a missing semver label', async () => { - const payload = loadFixture('pr-open-time/pull_request.semver-missing.json'); - const minTime = getMinimumOpenTime(payload); - - expect(minTime).toEqual(MINIMUM_MAJOR_OPEN_TIME); - }); - - it('correctly determines whether to exclude some PRs from labels', async () => { - const noLabelPayload = loadFixture('pr-open-time/pull_request.should_not_label.json'); - const yesLabelPayload = loadFixture('pr-open-time/pull_request.should_label.json'); - - // Set created_at to yesterday. - yesLabelPayload.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24 * 2); - - const yesLabel = await shouldPRHaveLabel(moctokit, yesLabelPayload); - const noLabel = await shouldPRHaveLabel(moctokit, noLabelPayload); - - expect(yesLabel).toEqual(true); - expect(noLabel).toEqual(false); - }); - - it('does not add the new-pr label to merged PRs', async () => { - const payload = loadFixture('pr-open-time/pull_request.should_label.json'); - payload.merged = true; - - const label = await shouldPRHaveLabel(moctokit, payload); - expect(label).toEqual(false); - }); - - it('correctly determines whether a label if relevant to the decision tree', () => { - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${NEW_PR_LABEL}`, - name: NEW_PR_LABEL, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${SEMVER_LABELS.MINOR}`, - name: SEMVER_LABELS.MINOR, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${SEMVER_LABELS.PATCH}`, - name: SEMVER_LABELS.PATCH, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${SEMVER_LABELS.MAJOR}`, - name: SEMVER_LABELS.PATCH, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${SEMVER_NONE_LABEL}`, - name: SEMVER_NONE_LABEL, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${BACKPORT_LABEL}`, - name: BACKPORT_LABEL, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${BACKPORT_SKIP_LABEL}`, - name: BACKPORT_SKIP_LABEL, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: `https://api.github.com/repos/electron/electron/labels/${FAST_TRACK_LABEL}`, - name: FAST_TRACK_LABEL, - color: '6ac2dd', - default: false, - }), - ).toEqual(true); - - expect( - labelShouldBeChecked({ - id: 12345, - description: '', - node_id: 'id', - url: 'https://api.github.com/repos/electron/electron/labels/random', - name: 'random', - color: '6ac2dd', - default: false, - }), - ).toEqual(false); - }); - - it(`can add a ${NEW_PR_LABEL} label to a pull request`, async () => { - const payload = loadFixture('pr-open-time/pull_request.opened.json'); - - // Set created_at to yesterday. - payload.pull_request.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24 * 2); - - // Timeline events (none) used by getPROpenedTime - nock(GH_API).get(`/repos/electron/electron/issues/${payload.number}/timeline`).reply(200, []); - - nock(GH_API) - .get(`/repos/electron/electron/issues/${payload.number}/labels?per_page=100&page=1`) - .reply(200, [{ name: 'one' }, { name: 'two' }]); - - nock(GH_API) - .post(`/repos/electron/electron/issues/${payload.number}/labels`, (body) => { - expect(body).toEqual({ labels: [NEW_PR_LABEL] }); - return true; - }) - .reply(200, { labels: [{ name: NEW_PR_LABEL }] }); - - await robot.receive({ - id: '123-456', - name: 'pull_request', - payload, - }); - }); - - it(`takes draft status into account when adding a ${NEW_PR_LABEL} label`, async () => { - const payload = loadFixture('pr-open-time/pull_request.opened.json'); - - // Set created_at to 5 days ago. - const msInADay = 1638370929101; - payload.pull_request.created_at = new Date(+new Date() - msInADay * 5); - - nock(GH_API) - .get(`/repos/electron/electron/issues/${payload.number}/timeline`) - .reply(200, [ - { - actor_name: 'codebytere', - created_at: new Date(+new Date() - 1000 * 60 * 60 * 24 * 2), - type: 'ready_for_review', - }, - ]); - - nock(GH_API) - .get(`/repos/electron/electron/issues/${payload.number}/labels?per_page=100&page=1`) - .reply(200, [{ name: 'one' }, { name: 'two' }]); - - await robot.receive({ - id: '123-456', - name: 'pull_request', - payload, - }); - }); -}); diff --git a/spec/api-review-state.spec.ts b/spec/api-review-state.spec.ts index 13144db..db1ead3 100644 --- a/spec/api-review-state.spec.ts +++ b/spec/api-review-state.spec.ts @@ -16,7 +16,7 @@ import { MINIMUM_MINOR_OPEN_TIME, MINIMUM_PATCH_OPEN_TIME, API_REVIEW_CHECK_NAME, - NEW_PR_LABEL, + API_SKIP_DELAY_LABEL, API_WORKING_GROUP, } from '../src/constants'; @@ -38,7 +38,7 @@ const API_WORKING_GROUP_MEMBERS = [ ]; const handler = async (app: Probot) => { - setupAPIReviewStateManagement(app); + setupAPIReviewStateManagement(app, true); }; describe('api review', () => { @@ -384,10 +384,42 @@ describe('api review', () => { }); }); - it(`should not update api review label if the PR has ${NEW_PR_LABEL}`, async () => { - const { pull_request } = loadFixture('api-review-state/pull_request.new-pr_label.json'); + it('should not update api review label if the PR has not passed its minimum open time', async () => { + const { pull_request } = loadFixture( + 'api-review-state/pull_request.requested_review_label.json', + ); + + // Set created_at to yesterday. + pull_request.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24).toISOString(); + await checkPRReadyForMerge(moctokit, pull_request, { - approved: [], + approved: ['jkleinsc', 'codebytere'], + declined: [], + requestedChanges: [], + }); + + expect(moctokit.rest.issues.addLabels).not.toHaveBeenCalled(); + expect(moctokit.rest.issues.removeLabel).not.toHaveBeenCalled(); + }); + + it('should not update api review label if the PR was marked ready for review within its minimum open time', async () => { + const { pull_request } = loadFixture( + 'api-review-state/pull_request.requested_review_label.json', + ); + + // PR was created 10 days ago but marked ready 2 days ago. + pull_request.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24 * 10).toISOString(); + moctokit.rest.issues.listEventsForTimeline = vi.fn().mockReturnValue({ + data: [ + { + event: 'ready_for_review', + created_at: new Date(+new Date() - 1000 * 60 * 60 * 24 * 2).toISOString(), + }, + ], + }); + + await checkPRReadyForMerge(moctokit, pull_request, { + approved: ['jkleinsc', 'codebytere'], declined: [], requestedChanges: [], }); @@ -396,6 +428,51 @@ describe('api review', () => { expect(moctokit.rest.issues.removeLabel).not.toHaveBeenCalled(); }); + it('should update api review label once the PR has passed its minimum open time', async () => { + const { pull_request } = loadFixture( + 'api-review-state/pull_request.requested_review_label.json', + ); + + // Set created_at to 8 days ago. + pull_request.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24 * 8).toISOString(); + + await checkPRReadyForMerge(moctokit, pull_request, { + approved: ['jkleinsc', 'codebytere'], + declined: [], + requestedChanges: [], + }); + + expect(moctokit.rest.issues.addLabels).toHaveBeenCalledWith({ + issue_number: pull_request.number, + labels: [REVIEW_LABELS.APPROVED], + owner: 'electron', + repo: 'electron', + }); + }); + + it(`should update api review label within the minimum open time if the PR has ${API_SKIP_DELAY_LABEL}`, async () => { + const { pull_request } = loadFixture( + 'api-review-state/pull_request.requested_review_label.json', + ); + + // Set created_at to yesterday. + pull_request.created_at = new Date(+new Date() - 1000 * 60 * 60 * 24).toISOString(); + pull_request.labels.push({ name: API_SKIP_DELAY_LABEL }); + + await checkPRReadyForMerge(moctokit, pull_request, { + approved: ['jkleinsc', 'codebytere'], + declined: [], + requestedChanges: [], + }); + + expect(moctokit.rest.issues.addLabels).toHaveBeenCalledWith({ + issue_number: pull_request.number, + labels: [REVIEW_LABELS.APPROVED], + owner: 'electron', + repo: 'electron', + }); + }); + it(`should update api review label for ${REVIEW_LABELS.DECLINED}`, async () => { const { pull_request } = loadFixture('api-review-state/pull_request.no_review_label.json'); @@ -563,6 +640,7 @@ describe('api review', () => { nock(GH_API) .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .times(2) .reply(200, []); nock(GH_API) @@ -620,6 +698,7 @@ describe('api review', () => { nock(GH_API) .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .times(2) .reply(200, []); nock(GH_API) @@ -718,6 +797,7 @@ describe('api review', () => { nock(GH_API) .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .times(2) .reply(200, []); nock(GH_API) @@ -805,6 +885,10 @@ describe('api review', () => { .get(`/repos/electron/electron/issues/${pull_request.number}/comments`) .reply(200, [c1]); + nock(GH_API) + .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .reply(200, []); + await robot.receive({ id: '123-456', name: 'pull_request_review', @@ -831,6 +915,10 @@ describe('api review', () => { .get(`/repos/electron/electron/issues/${pull_request.number}/comments`) .reply(200, [c1]); + nock(GH_API) + .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .reply(200, []); + nock(GH_API) .get(`/repos/electron/electron/issues/${pull_request.number}/labels?per_page=100&page=1`) .reply(200, [ @@ -895,6 +983,10 @@ describe('api review', () => { .get(`/repos/electron/electron/issues/${pull_request.number}/comments`) .reply(200, []); + nock(GH_API) + .get(`/repos/electron/electron/issues/${pull_request.number}/timeline`) + .reply(200, []); + nock(GH_API) .get(`/repos/electron/electron/issues/${pull_request.number}/labels?per_page=100&page=1`) .reply(200, [ diff --git a/spec/fixtures/api-review-state/pull_request.new-pr_label.json b/spec/fixtures/api-review-state/pull_request.new-pr_label.json deleted file mode 100644 index 797da45..0000000 --- a/spec/fixtures/api-review-state/pull_request.new-pr_label.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "pull_request": { - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=" - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1243058793, - "node_id": "MDU6TGFiZWwxMjQzMDU4Nzkz", - "url": "https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1", - "name": "new-pr 🌱", - "color": "8af297", - "default": false, - "description": "PR opened in the last 24 hours" - } - ], - "head": { - "label": "electron:fix-lint-js", - "ref": "fix-lint-js", - "sha": "c6b1b7168ab850a47f856c4a30f7a441bede1117", - "user": { - "login": "electron", - "id": 13409222, - "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy", - "avatar_url": "https://avatars.githubusercontent.com/u/13409222?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/electron", - "html_url": "https://github.com/electron", - "followers_url": "https://api.github.com/users/electron/followers", - "following_url": "https://api.github.com/users/electron/following{/other_user}", - "gists_url": "https://api.github.com/users/electron/gists{/gist_id}", - "starred_url": "https://api.github.com/users/electron/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/electron/subscriptions", - "organizations_url": "https://api.github.com/users/electron/orgs", - "repos_url": "https://api.github.com/users/electron/repos", - "events_url": "https://api.github.com/users/electron/events{/privacy}", - "received_events_url": "https://api.github.com/users/electron/received_events", - "type": "Organization", - "site_admin": false - }, - "repo": { - "id": 9384267, - "node_id": "MDEwOlJlcG9zaXRvcnk5Mzg0MjY3", - "name": "electron", - "full_name": "electron/electron", - "private": false, - "owner": { - "login": "electron", - "id": 13409222, - "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy", - "avatar_url": "https://avatars.githubusercontent.com/u/13409222?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/electron", - "html_url": "https://github.com/electron", - "followers_url": "https://api.github.com/users/electron/followers", - "following_url": "https://api.github.com/users/electron/following{/other_user}", - "gists_url": "https://api.github.com/users/electron/gists{/gist_id}", - "starred_url": "https://api.github.com/users/electron/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/electron/subscriptions", - "organizations_url": "https://api.github.com/users/electron/orgs", - "repos_url": "https://api.github.com/users/electron/repos", - "events_url": "https://api.github.com/users/electron/events{/privacy}", - "received_events_url": "https://api.github.com/users/electron/received_events", - "type": "Organization", - "site_admin": false - } - }, - "repository": { - "id": 9384267, - "node_id": "MDEwOlJlcG9zaXRvcnk5Mzg0MjY3", - "name": "electron", - "full_name": "electron/electron", - "private": false, - "owner": { - "login": "electron", - "id": 13409222 - }, - "license": { - "key": "mit", - "name": "MIT License", - "spdx_id": "MIT", - "url": "https://api.github.com/licenses/mit", - "node_id": "MDc6TGljZW5zZTEz" - } - } - } - } -} \ No newline at end of file diff --git a/spec/fixtures/api-review-state/pull_request.no_review_label.json b/spec/fixtures/api-review-state/pull_request.no_review_label.json index 501f64d..2634013 100644 --- a/spec/fixtures/api-review-state/pull_request.no_review_label.json +++ b/spec/fixtures/api-review-state/pull_request.no_review_label.json @@ -28,6 +28,8 @@ "labels": [], "base": { "repo": { + "name": "electron", + "full_name": "electron/electron", "owner": { "login": "electron" } diff --git a/spec/fixtures/pr-open-time/pull_request.opened.json b/spec/fixtures/pr-open-time/pull_request.opened.json deleted file mode 100644 index 0d78cb9..0000000 --- a/spec/fixtures/pr-open-time/pull_request.opened.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "action": "opened", - "number": 26876, - "pull_request": { - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/major", - "name": "semver/major", - "color": "6ac2dd", - "default": false, - "description": "backwards-incompatible bug fixes" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 - }, - "repository": { - "id": 9384267, - "node_id": "MDEwOlJlcG9zaXRvcnk5Mzg0MjY3", - "name": "electron", - "full_name": "electron/electron", - "private": false, - "owner": { - "login": "electron", - "id": 13409222, - "node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDA5MjIy", - "avatar_url": "https://avatars1.githubusercontent.com/u/13409222?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/electron", - "html_url": "https://github.com/electron", - "followers_url": "https://api.github.com/users/electron/followers", - "following_url": "https://api.github.com/users/electron/following{/other_user}", - "gists_url": "https://api.github.com/users/electron/gists{/gist_id}", - "starred_url": "https://api.github.com/users/electron/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/electron/subscriptions", - "organizations_url": "https://api.github.com/users/electron/orgs", - "repos_url": "https://api.github.com/users/electron/repos", - "events_url": "https://api.github.com/users/electron/events{/privacy}", - "received_events_url": "https://api.github.com/users/electron/received_events", - "type": "Organization", - "site_admin": false - }, - "html_url": "https://github.com/electron/electron", - "description": ":electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS", - "fork": false, - "url": "https://api.github.com/repos/electron/electron", - "forks_url": "https://api.github.com/repos/electron/electron/forks", - "keys_url": "https://api.github.com/repos/electron/electron/keys{/key_id}", - "collaborators_url": "https://api.github.com/repos/electron/electron/collaborators{/collaborator}", - "teams_url": "https://api.github.com/repos/electron/electron/teams", - "hooks_url": "https://api.github.com/repos/electron/electron/hooks", - "issue_events_url": "https://api.github.com/repos/electron/electron/issues/events{/number}", - "events_url": "https://api.github.com/repos/electron/electron/events", - "assignees_url": "https://api.github.com/repos/electron/electron/assignees{/user}", - "branches_url": "https://api.github.com/repos/electron/electron/branches{/branch}", - "tags_url": "https://api.github.com/repos/electron/electron/tags", - "blobs_url": "https://api.github.com/repos/electron/electron/git/blobs{/sha}", - "git_tags_url": "https://api.github.com/repos/electron/electron/git/tags{/sha}", - "git_refs_url": "https://api.github.com/repos/electron/electron/git/refs{/sha}", - "trees_url": "https://api.github.com/repos/electron/electron/git/trees{/sha}", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/{sha}", - "languages_url": "https://api.github.com/repos/electron/electron/languages", - "stargazers_url": "https://api.github.com/repos/electron/electron/stargazers", - "contributors_url": "https://api.github.com/repos/electron/electron/contributors", - "subscribers_url": "https://api.github.com/repos/electron/electron/subscribers", - "subscription_url": "https://api.github.com/repos/electron/electron/subscription", - "commits_url": "https://api.github.com/repos/electron/electron/commits{/sha}", - "git_commits_url": "https://api.github.com/repos/electron/electron/git/commits{/sha}", - "comments_url": "https://api.github.com/repos/electron/electron/comments{/number}", - "issue_comment_url": "https://api.github.com/repos/electron/electron/issues/comments{/number}", - "contents_url": "https://api.github.com/repos/electron/electron/contents/{+path}", - "compare_url": "https://api.github.com/repos/electron/electron/compare/{base}...{head}", - "merges_url": "https://api.github.com/repos/electron/electron/merges", - "archive_url": "https://api.github.com/repos/electron/electron/{archive_format}{/ref}", - "downloads_url": "https://api.github.com/repos/electron/electron/downloads", - "issues_url": "https://api.github.com/repos/electron/electron/issues{/number}", - "pulls_url": "https://api.github.com/repos/electron/electron/pulls{/number}", - "milestones_url": "https://api.github.com/repos/electron/electron/milestones{/number}", - "notifications_url": "https://api.github.com/repos/electron/electron/notifications{?since,all,participating}", - "labels_url": "https://api.github.com/repos/electron/electron/labels{/name}", - "releases_url": "https://api.github.com/repos/electron/electron/releases{/id}", - "deployments_url": "https://api.github.com/repos/electron/electron/deployments", - "created_at": "2013-04-12T01:47:36Z", - "updated_at": "2020-12-08T00:51:34Z", - "pushed_at": "2020-12-08T01:24:47Z", - "git_url": "git://github.com/electron/electron.git", - "ssh_url": "git@github.com:electron/electron.git", - "clone_url": "https://github.com/electron/electron.git", - "svn_url": "https://github.com/electron/electron", - "homepage": "https://electronjs.org", - "size": 87927, - "stargazers_count": 87932, - "watchers_count": 87932, - "language": "C++", - "has_issues": true, - "has_projects": true, - "has_downloads": true, - "has_wiki": false, - "has_pages": false, - "forks_count": 11755, - "mirror_url": null, - "archived": false, - "disabled": false, - "open_issues_count": 1525, - "license": { - "key": "mit", - "name": "MIT License", - "spdx_id": "MIT", - "url": "https://api.github.com/licenses/mit", - "node_id": "MDc6TGljZW5zZTEz" - }, - "forks": 11755, - "open_issues": 1525, - "watchers": 87932, - "default_branch": "main" - }, - "installation": { - "id": 690857 - } -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.semver-major.json b/spec/fixtures/pr-open-time/pull_request.semver-major.json deleted file mode 100644 index f5c5516..0000000 --- a/spec/fixtures/pr-open-time/pull_request.semver-major.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/major", - "name": "semver/major", - "color": "6ac2dd", - "default": false, - "description": "backwards-incompatible bug fixes" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.semver-minor.json b/spec/fixtures/pr-open-time/pull_request.semver-minor.json deleted file mode 100644 index 4e5c6e3..0000000 --- a/spec/fixtures/pr-open-time/pull_request.semver-minor.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/minor", - "name": "semver/minor", - "color": "6ac2dd", - "default": false, - "description": "new features" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.semver-missing.json b/spec/fixtures/pr-open-time/pull_request.semver-missing.json deleted file mode 100644 index d12dfb9..0000000 --- a/spec/fixtures/pr-open-time/pull_request.semver-missing.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "build: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ ], - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.semver-none.json b/spec/fixtures/pr-open-time/pull_request.semver-none.json deleted file mode 100644 index 34809e9..0000000 --- a/spec/fixtures/pr-open-time/pull_request.semver-none.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/none", - "name": "semver/none", - "color": "6ac2dd", - "default": false, - "description": "new features" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.semver-patch.json b/spec/fixtures/pr-open-time/pull_request.semver-patch.json deleted file mode 100644 index 1189ad8..0000000 --- a/spec/fixtures/pr-open-time/pull_request.semver-patch.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "build: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/patch", - "name": "semver/patch", - "color": "6ac2dd", - "default": false, - "description": "backwards-compatible bug fixes" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.should_label.json b/spec/fixtures/pr-open-time/pull_request.should_label.json deleted file mode 100644 index 4e5c6e3..0000000 --- a/spec/fixtures/pr-open-time/pull_request.should_label.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "chore: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [ - { - "id": 1034512799, - "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", - "url": "https://api.github.com/repos/electron/electron/labels/semver/minor", - "name": "semver/minor", - "color": "6ac2dd", - "default": false, - "description": "new features" - } - ], - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/pr-open-time/pull_request.should_not_label.json b/spec/fixtures/pr-open-time/pull_request.should_not_label.json deleted file mode 100644 index b56e2d0..0000000 --- a/spec/fixtures/pr-open-time/pull_request.should_not_label.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "url": "https://api.github.com/repos/electron/electron/pulls/26876", - "id": 534054584, - "node_id": "MDExOlB1bGxSZXF1ZXN0NTM0MDU0NTg0", - "html_url": "https://github.com/electron/electron/pull/26876", - "diff_url": "https://github.com/electron/electron/pull/26876.diff", - "patch_url": "https://github.com/electron/electron/pull/26876.patch", - "issue_url": "https://api.github.com/repos/electron/electron/issues/26876", - "number": 26876, - "state": "open", - "locked": false, - "title": "build: fix JS linting", - "user": { - "login": "MarshallOfSound", - "id": 6634592, - "node_id": "MDQ6VXNlcjY2MzQ1OTI=", - "avatar_url": "https://avatars3.githubusercontent.com/u/6634592?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/MarshallOfSound", - "html_url": "https://github.com/MarshallOfSound", - "followers_url": "https://api.github.com/users/MarshallOfSound/followers", - "following_url": "https://api.github.com/users/MarshallOfSound/following{/other_user}", - "gists_url": "https://api.github.com/users/MarshallOfSound/gists{/gist_id}", - "starred_url": "https://api.github.com/users/MarshallOfSound/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/MarshallOfSound/subscriptions", - "organizations_url": "https://api.github.com/users/MarshallOfSound/orgs", - "repos_url": "https://api.github.com/users/MarshallOfSound/repos", - "events_url": "https://api.github.com/users/MarshallOfSound/events{/privacy}", - "received_events_url": "https://api.github.com/users/MarshallOfSound/received_events", - "type": "User", - "site_admin": false - }, - "base": { - "repo": { - "full_name": "electron/electron" - } - }, - "body": "* Ensure --fix output is actually written to disk\r\n* Cache bust on lint.js file changes\r\n* Ensure CI does not use the linting cache\r\n\r\nNotes: no-notes", - "created_at": "2020-12-08T01:24:55Z", - "updated_at": "2020-12-08T01:24:55Z", - "closed_at": null, - "merged_at": null, - "merge_commit_sha": null, - "assignee": null, - "labels": [], - "milestone": null, - "draft": false, - "commits_url": "https://api.github.com/repos/electron/electron/pulls/26876/commits", - "review_comments_url": "https://api.github.com/repos/electron/electron/pulls/26876/comments", - "review_comment_url": "https://api.github.com/repos/electron/electron/pulls/comments{/number}", - "comments_url": "https://api.github.com/repos/electron/electron/issues/26876/comments", - "statuses_url": "https://api.github.com/repos/electron/electron/statuses/578fd4af98861ef7e6374d7d1fa1ccca6bc7136d", - "author_association": "MEMBER", - "active_lock_reason": null, - "merged": false, - "mergeable": null, - "rebaseable": null, - "mergeable_state": "unknown", - "merged_by": null, - "comments": 0, - "review_comments": 0, - "maintainer_can_modify": false, - "commits": 1, - "additions": 12, - "deletions": 5, - "changed_files": 2 -} \ No newline at end of file diff --git a/spec/fixtures/semver-enforcement/pull_request.labeled.json b/spec/fixtures/semver-enforcement/pull_request.labeled.json index 9613fbb..0a77aa9 100644 --- a/spec/fixtures/semver-enforcement/pull_request.labeled.json +++ b/spec/fixtures/semver-enforcement/pull_request.labeled.json @@ -44,15 +44,6 @@ "requested_reviewers": [], "requested_teams": [], "labels": [ - { - "id": 1243058793, - "node_id": "MDU6TGFiZWwxMjQzMDU4Nzkz", - "url": "https://api.github.com/repos/electron/electron/labels/new-pr%20%F0%9F%8C%B1", - "name": "new-pr 🌱", - "color": "8af297", - "default": false, - "description": "PR opened in the last 24 hours" - }, { "id": 1034512799, "node_id": "MDU6TGFiZWwxMDM0NTEyNzk5", diff --git a/src/24-hour-rule.ts b/src/24-hour-rule.ts deleted file mode 100644 index d40d45d..0000000 --- a/src/24-hour-rule.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { Context, Probot } from 'probot'; - -import { - NEW_PR_LABEL, - EXCLUDE_LABELS, - EXCLUDE_PREFIXES, - EXCLUDE_USERS, - SEMVER_LABELS, - MINIMUM_MAJOR_OPEN_TIME, - MINIMUM_PATCH_OPEN_TIME, - MINIMUM_MINOR_OPEN_TIME, - SEMVER_NONE_LABEL, -} from './constants'; -import { addOrUpdateAPIReviewCheck, checkPRReadyForMerge } from './api-review-state'; -import { log } from './utils/log-util'; -import { addLabels, removeLabel } from './utils/label-utils'; -import { LogLevel } from './enums'; -import { PullRequest, Label, PullRequestLabeledEvent } from './types'; -import { getPROpenedTime } from './utils/pr-open-time-util'; - -const CHECK_INTERVAL = 1000 * 60 * 5; - -/** - * @returns a number representing the minimum open time for the PR - * based on its semantic prefix in milliseconds - */ -export const getMinimumOpenTime = (pr: PullRequest): number => { - log('getMinimumOpenTime', LogLevel.INFO, `Fetching minimum open time for PR #${pr.number}.`); - - const hasLabel = (label: string) => pr.labels.some((l) => l.name === label); - - if (hasLabel(SEMVER_LABELS.MAJOR)) return MINIMUM_MAJOR_OPEN_TIME; - if (hasLabel(SEMVER_LABELS.MINOR)) return MINIMUM_MINOR_OPEN_TIME; - if (hasLabel(SEMVER_LABELS.PATCH) || hasLabel(SEMVER_NONE_LABEL)) return MINIMUM_PATCH_OPEN_TIME; - - // If it's not labeled yet, assume it is semver/major and do not remove the label. - return MINIMUM_MAJOR_OPEN_TIME; -}; - -export const shouldPRHaveLabel = async ( - github: Context['octokit'], - pr: PullRequest, -): Promise => { - log('shouldPRHaveLabel', LogLevel.INFO, `Checking whether #${pr.number} should have label.`); - - const prefix = pr.title.split(':')[0]; - const backportMatch = pr.title.match(/[bB]ackport/); - const backportInTitle = backportMatch && backportMatch[0]; - const hasExcludedLabel = pr.labels.some((label) => EXCLUDE_LABELS.includes(label.name)); - - if ( - EXCLUDE_PREFIXES.includes(prefix) || - hasExcludedLabel || - backportInTitle || - EXCLUDE_USERS.includes(pr.user.login) || - pr.merged - ) - return false; - - const created = await getPROpenedTime(github, pr); - const now = Date.now(); - - return now - created < getMinimumOpenTime(pr); -}; - -export const applyLabelToPR = async ( - github: Context['octokit'], - pr: PullRequest, - shouldHaveLabel: boolean, -) => { - const [owner, repo] = pr.base.repo.full_name.split('/'); - - if (shouldHaveLabel) { - log( - 'applyLabelToPR', - LogLevel.INFO, - `Found PR ${owner}/${repo}#${pr.number} - should ensure ${NEW_PR_LABEL} label exists.`, - ); - - await addLabels(github, { - prNumber: pr.number, - labels: [NEW_PR_LABEL], - repo, - owner, - }); - } else { - log( - 'applyLabelToPR', - LogLevel.INFO, - `Found PR ${owner}/${repo}#${pr.number} - should ensure ${NEW_PR_LABEL} label does not exist.`, - ); - - try { - await removeLabel(github, { - owner, - repo, - prNumber: pr.number, - name: NEW_PR_LABEL, - }); - - pr.labels = pr.labels.filter((l) => l.name !== NEW_PR_LABEL); - await addOrUpdateAPIReviewCheck(github, pr); - } catch { - // Ignore the error here, it's a race condition between the Cron job and GitHub webhooks - } - } -}; - -// Returns whether or not a label is relevant to the new-pr decision tree. -export const labelShouldBeChecked = (label: Label) => { - const relevantLabels = [ - NEW_PR_LABEL, - SEMVER_NONE_LABEL, - ...Object.values(SEMVER_LABELS), - ...EXCLUDE_LABELS, - ]; - return relevantLabels.includes(label.name); -}; - -export async function setUp24HourRule(probot: Probot, disableCronForTesting = false) { - probot.on( - ['pull_request.opened', 'pull_request.unlabeled', 'pull_request.labeled'], - async (context) => { - const { action, pull_request: pr, repository } = context.payload; - - // We only care about user labels adds for new-pr and semver labels. - if (action === 'labeled' || action === 'unlabeled') { - const { label } = context.payload as PullRequestLabeledEvent; - if (!labelShouldBeChecked(label!)) return; - } - - probot.log.info( - `24-hour rule received PR: ${repository.full_name}#${pr.number} checking now`, - ); - - const shouldLabel = await shouldPRHaveLabel(context.octokit, pr as PullRequest); - - await applyLabelToPR(context.octokit, pr as PullRequest, shouldLabel); - }, - ); - - if (!disableCronForTesting) runInterval(); - - async function runInterval() { - probot.log.info('Running 24 hour rule check'); - const github = await probot.auth(); - const { data: installs } = await github.rest.apps.listInstallations({}); - for (const install of installs) { - try { - await runCron(probot, install.id); - } catch (err) { - probot.log.error(`Failed to run cron for install: ${install.id} ${err}`); - } - } - - setTimeout(runInterval, CHECK_INTERVAL); - } - - async function runCron(probot: Probot, installId: number) { - const octokit = await probot.auth(installId); - const { data } = await octokit.rest.apps.listReposAccessibleToInstallation({}); - - for (const repo of data.repositories) { - probot.log.info(`Running 24 hour cron job on repo: ${repo.owner.login}/${repo.name}`); - let page = 0; - const prs: PullRequest[] = []; - let lastPRCount = -1; - do { - lastPRCount = prs.length; - prs.push( - ...(( - await octokit.rest.pulls.list({ - owner: repo.owner.login, - repo: repo.name, - per_page: 100, - state: 'open', - page, - }) - ).data as unknown as PullRequest[]), - ); - page++; - } while (lastPRCount < prs.length); - - probot.log.info(`Found ${prs.length} prs for repo: ${repo.owner.login}/${repo.name}`); - - for (const pr of prs) { - const shouldLabel = await shouldPRHaveLabel(octokit, pr); - - // Ensure that API review labels are updated after waiting period. - if (!shouldLabel) { - const approvalState = await addOrUpdateAPIReviewCheck(octokit, pr); - await checkPRReadyForMerge(octokit, pr, approvalState); - } - - await applyLabelToPR(octokit, pr, shouldLabel); - } - } - } -} diff --git a/src/api-review-state.ts b/src/api-review-state.ts index 85c3c5e..c105d5c 100644 --- a/src/api-review-state.ts +++ b/src/api-review-state.ts @@ -8,7 +8,6 @@ import { EXCLUDE_LABELS, MINIMUM_MINOR_OPEN_TIME, MINIMUM_PATCH_OPEN_TIME, - NEW_PR_LABEL, OWNER, REPO, REVIEW_LABELS, @@ -17,11 +16,13 @@ import { import { CheckRunStatus, LogLevel } from './enums'; import { isAPIReviewRequired } from './utils/check-utils'; import { getEnvVar } from './utils/env-util'; -import { PullRequest, Label } from './types'; +import { PullRequest } from './types'; import { GetResponseDataTypeFromEndpointMethod, Endpoints } from '@octokit/types'; import { addLabels, removeLabel } from './utils/label-utils'; import { getPROpenedTime } from './utils/pr-open-time-util'; +const CHECK_INTERVAL = 1000 * 60 * 5; + type APIApprovalState = ReturnType extends Promise ? T : unknown; @@ -41,17 +42,20 @@ export const hasAPIReviewRequestedLabel = (pr: PullRequest) => pr.labels.some((l) => l.name === REVIEW_LABELS.REQUESTED); /** - * Determines the PR readiness date depending on its semver label. + * Determines the PR readiness time depending on its semver label. * - * @returns a date corresponding to the time that must elapse before a PR requiring - * API review is ready to be merged according to its semver label. + * @returns a number representing the time in milliseconds that must be reached before + * a PR requiring API review is ready to be merged according to its semver label. */ -export const getPRReadyDate = async (octokit: Context['octokit'], pr: PullRequest) => { +export const getPRReadyTime = async ( + octokit: Context['octokit'], + pr: PullRequest, +): Promise => { let readyTime = await getPROpenedTime(octokit, pr); if (pr.labels.some((l) => l.name === API_SKIP_DELAY_LABEL)) { log( - 'getPRReadyDate', + 'getPRReadyTime', LogLevel.INFO, `${pr.number} has "${API_SKIP_DELAY_LABEL}" label - skipping minimum open time`, ); @@ -59,7 +63,7 @@ export const getPRReadyDate = async (octokit: Context['octokit'], pr: PullReques const isMajorMinor = pr.labels.some((l) => isSemverMajorMinorLabel(l.name)); readyTime += isMajorMinor ? MINIMUM_MINOR_OPEN_TIME : MINIMUM_PATCH_OPEN_TIME; log( - 'getPRReadyDate', + 'getPRReadyTime', LogLevel.INFO, `${pr.number} has no "${API_SKIP_DELAY_LABEL}" label - applying minimum open time for ${ isMajorMinor ? 'major/minor' : 'patch' @@ -67,7 +71,24 @@ export const getPRReadyDate = async (octokit: Context['octokit'], pr: PullReques ); } - return new Date(readyTime).toISOString().split('T')[0]; + return readyTime; +}; + +/** + * Determines the PR readiness date depending on its semver label. + * + * @returns a date corresponding to the time that must elapse before a PR requiring + * API review is ready to be merged according to its semver label. + */ +export const getPRReadyDate = async (octokit: Context['octokit'], pr: PullRequest) => { + return new Date(await getPRReadyTime(octokit, pr)).toISOString().split('T')[0]; +}; + +/** + * @returns whether or not a PR requiring API review has been open for its minimum open time. + */ +export const hasPRPassedMinimumOpenTime = async (octokit: Context['octokit'], pr: PullRequest) => { + return Date.now() >= (await getPRReadyTime(octokit, pr)); }; export async function addOrUpdateAPIReviewCheck(octokit: Context['octokit'], pr: PullRequest) { @@ -385,8 +406,17 @@ export async function checkPRReadyForMerge( } }; - const isNewPR = pr.labels.some((l: Label) => l.name === NEW_PR_LABEL); - if (!userApprovalState || isNewPR) return; + if (!userApprovalState) return; + + // The API review outcome is not applied until the PR has been open for its minimum open time. + if (!(await hasPRPassedMinimumOpenTime(octokit, pr))) { + log( + 'checkPRReadyForMerge', + LogLevel.INFO, + `${pr.number} has not passed its minimum open time - not updating API review label`, + ); + return; + } const { approved, declined, requestedChanges } = userApprovalState; if (declined.length > 0) { @@ -401,7 +431,7 @@ export async function checkPRReadyForMerge( } } -export function setupAPIReviewStateManagement(probot: Probot) { +export function setupAPIReviewStateManagement(probot: Probot, disableCronForTesting = false) { /** * If a PR is opened or synchronized, we want to ensure the * API review check is up-to-date. @@ -603,4 +633,52 @@ export function setupAPIReviewStateManagement(probot: Probot) { await addOrUpdateAPIReviewCheck(context.octokit, pr); } }); + + if (!disableCronForTesting) runInterval(); + + /** + * No webhook is sent when a PR passes its minimum open time, so periodically + * ensure the API review state is up-to-date for PRs undergoing API review. + */ + async function runInterval() { + probot.log.info('Running API review state check'); + const github = await probot.auth(); + const { data: installs } = await github.rest.apps.listInstallations({}); + for (const install of installs) { + try { + await runCron(install.id); + } catch (err) { + probot.log.error(`Failed to run cron for install: ${install.id} ${err}`); + } + } + + setTimeout(runInterval, CHECK_INTERVAL); + } + + async function runCron(installId: number) { + const octokit = await probot.auth(installId); + const { data } = await octokit.rest.apps.listReposAccessibleToInstallation({}); + + for (const repo of data.repositories) { + probot.log.info(`Running API review cron job on repo: ${repo.owner.login}/${repo.name}`); + + const prs = (await octokit.paginate(octokit.rest.pulls.list, { + owner: repo.owner.login, + repo: repo.name, + per_page: 100, + state: 'open', + })) as unknown as PullRequest[]; + + const reviewPRs = prs.filter((pr) => pr.labels.some((l) => isReviewLabel(l.name))); + + probot.log.info( + `Found ${reviewPRs.length} prs undergoing API review for repo: ${repo.owner.login}/${repo.name}`, + ); + + for (const pr of reviewPRs) { + const approvalState = await addOrUpdateAPIReviewCheck(octokit, pr); + await checkPRReadyForMerge(octokit, pr, approvalState); + } + } + } } diff --git a/src/constants.ts b/src/constants.ts index 9d5184e..b925824 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,11 +3,8 @@ export const ONE_HOUR = 1000 * 60 * 60; export const MINIMUM_PATCH_OPEN_TIME = ONE_HOUR * 24; // 168 Hour Minimum Time export const MINIMUM_MINOR_OPEN_TIME = ONE_HOUR * 24 * 7; -// 168 Hour Minimum Time -export const MINIMUM_MAJOR_OPEN_TIME = ONE_HOUR * 24 * 7; // backport type labels -export const NEW_PR_LABEL = 'new-pr 🌱'; export const BACKPORT_LABEL = 'backport'; export const BACKPORT_SKIP_LABEL = 'backport-check-skip'; export const FAST_TRACK_LABEL = 'fast-track 🚅'; @@ -61,5 +58,3 @@ export const API_WORKING_GROUP = 'wg-api'; // exclusion labels export const EXCLUDE_LABELS = [BACKPORT_LABEL, BACKPORT_SKIP_LABEL, FAST_TRACK_LABEL]; -export const EXCLUDE_PREFIXES = ['build', 'ci', 'test']; -export const EXCLUDE_USERS = ['roller-bot[bot]', 'electron-bot', 'trop[bot]']; diff --git a/src/index.ts b/src/index.ts index 070938d..a52911b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,6 @@ if (process.env.SENTRY_DSN) { } import { Probot } from 'probot'; -import { setUp24HourRule } from './24-hour-rule'; import { setupSemverLabelEnforcement } from './enforce-semver-labels'; import { setupAPIReviewStateManagement } from './api-review-state'; import { addBasicPRLabels } from './add-triage-labels'; @@ -27,7 +26,6 @@ const probotHandler = async (app: Probot) => { } } }); - setUp24HourRule(app); setupSemverLabelEnforcement(app); setupAPIReviewStateManagement(app); addBasicPRLabels(app); diff --git a/src/types.ts b/src/types.ts index a2c39bc..f39f6bd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,9 +3,7 @@ import { components } from '@octokit/openapi-webhooks-types'; type Schemas = components['schemas']; export type PullRequest = Schemas['pull-request']; -export type Label = Schemas['label']; export type IssueCommentEvent = Schemas[ | 'webhook-issue-comment-created' | 'webhook-issue-comment-edited']['comment']; -export type PullRequestLabeledEvent = Schemas['webhook-pull-request-labeled'];