Skip to content

Commit

Permalink
feat: better draft support (#325)
Browse files Browse the repository at this point in the history
  • Loading branch information
christophehurpeau committed Nov 10, 2021
1 parent 85c724f commit 201a57b
Show file tree
Hide file tree
Showing 10 changed files with 752 additions and 5 deletions.
531 changes: 531 additions & 0 deletions fixtures/pull_request_54.ready_for_review.json

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions fixtures/pull_request_54_draft-statuses.json
@@ -0,0 +1,34 @@
[
{
"url": "https://api.github.com/repos/reviewflow/reviewflow-test/statuses/f354ffb37cf238108fbb4c915f155d925d82a61b",
"avatar_url": "https://avatars.githubusercontent.com/u/302891?v=4",
"id": 15170493986,
"node_id": "SC_kwDOCgFbpc8AAAADiDteIg",
"state": "failure",
"description": "PR is still in draft",
"target_url": null,
"context": "reviewflow-dev",
"created_at": "2021-11-10T16:24:07Z",
"updated_at": "2021-11-10T16:24:07Z",
"creator": {
"login": "reviewflow-dev[bot]",
"id": 47090515,
"node_id": "MDM6Qm90NDcwOTA1MTU=",
"avatar_url": "https://avatars.githubusercontent.com/u/302891?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D",
"html_url": "https://github.com/apps/reviewflow-dev",
"followers_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/followers",
"following_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/following{/other_user}",
"gists_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/gists{/gist_id}",
"starred_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/subscriptions",
"organizations_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/orgs",
"repos_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/repos",
"events_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/events{/privacy}",
"received_events_url": "https://api.github.com/users/reviewflow-dev%5Bbot%5D/received_events",
"type": "Bot",
"site_admin": false
}
}
]
4 changes: 4 additions & 0 deletions src/events/pr-handlers/actions/updateStatusCheckFromLabels.ts
Expand Up @@ -84,6 +84,10 @@ export const updateStatusCheckFromLabels = <
previousSha,
);

if (pullRequest.draft) {
return createFailedStatusCheck('PR is still in draft');
}

if (
(pullRequest.requested_reviewers &&
pullRequest.requested_reviewers.length > 0) ||
Expand Down
41 changes: 41 additions & 0 deletions src/events/pr-handlers/convertedToDraft.ts
@@ -0,0 +1,41 @@
import type { Probot } from 'probot';
import type { AppContext } from '../../context/AppContext';
import { editOpenedPR } from './actions/editOpenedPR';
import { updateReviewStatus } from './actions/updateReviewStatus';
import { createPullRequestHandler } from './utils/createPullRequestHandler';

export default function convertedToDraft(
app: Probot,
appContext: AppContext,
): void {
createPullRequestHandler(
app,
appContext,
'pull_request.converted_to_draft',
(payload, context, repoContext) => {
return payload.pull_request;
},
async (
pullRequest,
context,
repoContext,
reviewflowPrContext,
): Promise<void> => {
/* if repo is not ignored */
if (reviewflowPrContext) {
await Promise.all([
updateReviewStatus(pullRequest, context, repoContext, 'dev', {
remove: ['needsReview'],
}),
editOpenedPR(
pullRequest,
context,
repoContext,
reviewflowPrContext,
true,
),
]);
}
},
);
}
7 changes: 4 additions & 3 deletions src/events/pr-handlers/opened.ts
Expand Up @@ -51,9 +51,10 @@ export default function opened(app: Probot, appContext: AppContext): void {
}),
)
: updateReviewStatus(pullRequest, context, repoContext, 'dev', {
add: repoContext.config.requiresReviewRequest
? ['needsReview']
: [],
add:
repoContext.config.requiresReviewRequest && !pullRequest.draft
? ['needsReview']
: [],
remove: ['approved', 'changesRequested'],
}),
]);
Expand Down
85 changes: 85 additions & 0 deletions src/events/pr-handlers/readyForReview.test.ts
@@ -0,0 +1,85 @@
import type { Probot } from 'probot';
import pullRequestCommits from '../../../fixtures/pull_request_30_commits.json';
import pullRequestReadyForReview from '../../../fixtures/pull_request_54.ready_for_review.json';
import * as initTeamSlack from '../../context/slack/initTeamSlack';
import { voidTeamSlack } from '../../context/slack/voidTeamSlack';
import {
initializeProbotApp,
mockAccessToken,
mockLabels,
nock,
} from '../../tests/setup';

jest.spyOn(initTeamSlack, 'initTeamSlack').mockResolvedValue(voidTeamSlack());

nock.disableNetConnect();

describe('edited', (): void => {
let probot: Probot;

beforeEach(async () => {
probot = await initializeProbotApp();
mockAccessToken();
mockLabels();
});

test('add code review label when pr is ready to be review', async (): Promise<void> => {
const scope = nock('https://api.github.com')
.get(
'/repos/reviewflow/reviewflow-test/issues/comments/1?issue_number=54',
)
.times(1)
.reply(200, {
id: 1,
body: '### Options:\n- [ ] <!-- reviewflow-autoMergeWithSkipCi -->Add `[skip ci]` on merge commit\n- [ ] <!-- reviewflow-autoMerge -->Auto merge when this PR is ready and has no failed statuses. (Also has a queue per repo to prevent multiple useless "Update branch" triggers)\n- [x] <!-- reviewflow-deleteAfterMerge -->Automatic branch delete after this PR is merged',
})

.get(
'/repos/reviewflow/reviewflow-test/commits/f354ffb37cf238108fbb4c915f155d925d82a61b/check-runs',
)
.times(2)
.reply(200, { check_runs: [] })

.get('/repos/reviewflow/reviewflow-test/pulls/54/commits?per_page=100')
.reply(200, pullRequestCommits)

.post(
'/repos/reviewflow/reviewflow-test/issues/54/labels',
'[":ok_hand: code/needs-review"]',
)
.reply(200, [
{
id: 1_210_432_920,
node_id: 'MDU6TGFiZWwxMjEwNDMyOTIw',
url: 'https://api.github.com/repos/reviewflow/reviewflow-test/labels/:ok_hand:%20code/needs-review',
name: ':ok_hand: code/needs-review',
color: 'FFD57F',
default: false,
description: null,
},
])

.post(
'/repos/reviewflow/reviewflow-test/statuses/f354ffb37cf238108fbb4c915f155d925d82a61b',
'{"context":"reviewflow-dev/lint-pr","state":"success","description":"✓ PR is valid"}',
)
.times(1)
.reply(200)

.post(
'/repos/reviewflow/reviewflow-test/statuses/f354ffb37cf238108fbb4c915f155d925d82a61b',
'{"context":"reviewflow-dev","state":"failure","description":"Awaiting review from: dev. Perhaps request someone ?"}',
)
.times(1)
.reply(200);

await probot.receive({
id: '1',
name: pullRequestReadyForReview.event as any,
payload: pullRequestReadyForReview.payload as any,
});

expect(scope.pendingMocks()).toEqual([]);
expect(scope.activeMocks()).toEqual([]);
});
});
41 changes: 41 additions & 0 deletions src/events/pr-handlers/readyForReview.ts
@@ -0,0 +1,41 @@
import type { Probot } from 'probot';
import type { AppContext } from '../../context/AppContext';
import { editOpenedPR } from './actions/editOpenedPR';
import { updateReviewStatus } from './actions/updateReviewStatus';
import { createPullRequestHandler } from './utils/createPullRequestHandler';

export default function readyForReview(
app: Probot,
appContext: AppContext,
): void {
createPullRequestHandler(
app,
appContext,
'pull_request.ready_for_review',
(payload, context, repoContext) => {
return payload.pull_request;
},
async (
pullRequest,
context,
repoContext,
reviewflowPrContext,
): Promise<void> => {
/* if repo is not ignored */
if (reviewflowPrContext) {
await Promise.all([
updateReviewStatus(pullRequest, context, repoContext, 'dev', {
add: ['needsReview'],
}),
editOpenedPR(
pullRequest,
context,
repoContext,
reviewflowPrContext,
true,
),
]);
}
},
);
}
5 changes: 3 additions & 2 deletions src/events/pr-handlers/reopened.ts
Expand Up @@ -22,12 +22,13 @@ export default function reopened(app: Probot, appContext: AppContext): void {
repoContext,
reviewflowPrContext,
): Promise<void> => {
const fromRenovate = pullRequest.head.ref.startsWith('renovate/');
/* if repo is not ignored */
if (reviewflowPrContext) {
await Promise.all([
updateReviewStatus(pullRequest, context, repoContext, 'dev', {
add: ['needsReview'],
remove: ['approved'],
add: fromRenovate || pullRequest.draft ? [] : ['needsReview'],
remove: fromRenovate ? [] : ['approved'],
}),
editOpenedPR(
pullRequest,
Expand Down
5 changes: 5 additions & 0 deletions src/events/pr-handlers/reviewRequestRemoved.ts
Expand Up @@ -75,6 +75,11 @@ export default function reviewRequestRemoved(
remove: [
approved && 'needsReview',
!hasRequestedReviewsForGroup && 'requested',
pullRequest.draft &&
!hasRequestedReviewsForGroup &&
!hasChangesRequestedInReviews
? 'needsReview'
: undefined,
],
},
);
Expand Down
4 changes: 4 additions & 0 deletions src/initApp.ts
Expand Up @@ -9,9 +9,11 @@ import checksuiteCompleted from './events/pr-handlers/checksuiteCompleted';
import closedHandler from './events/pr-handlers/closed';
import commentCreated from './events/pr-handlers/commentCreated';
import commentEditedOrDeleted from './events/pr-handlers/commentEditedOrDeleted';
import convertedToDraft from './events/pr-handlers/convertedToDraft';
import editedHandler from './events/pr-handlers/edited';
import labelsChanged from './events/pr-handlers/labelsChanged';
import openedHandler from './events/pr-handlers/opened';
import readyForReview from './events/pr-handlers/readyForReview';
import reopenedHandler from './events/pr-handlers/reopened';
import reviewDismissedHandler from './events/pr-handlers/reviewDismissed';
import reviewRequestRemovedHandler from './events/pr-handlers/reviewRequestRemoved';
Expand Down Expand Up @@ -40,6 +42,8 @@ export default function initApp(app: Probot, appContext: AppContext): void {
editedHandler(app, appContext);
closedHandler(app, appContext);
reopenedHandler(app, appContext);
convertedToDraft(app, appContext);
readyForReview(app, appContext);

reviewRequestedHandler(app, appContext);
reviewRequestRemovedHandler(app, appContext);
Expand Down

0 comments on commit 201a57b

Please sign in to comment.