Skip to content

Commit

Permalink
feat: add actions in reviewflow comment
Browse files Browse the repository at this point in the history
  • Loading branch information
christophehurpeau committed Jan 22, 2022
1 parent 1a29530 commit a49fdef
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
import type { EventsWithRepository, RepoContext } from 'context/repoContext';
import type { ProbotEvent } from 'events/probot-types';
import type {
PullRequestFromRestEndpoint,
PullRequestWithDecentData,
} from '../utils/PullRequestData';
import type { AppContext } from '../../../context/AppContext';
import type { PullRequestFromRestEndpoint } from '../utils/PullRequestData';
import type { ReviewflowPrContext } from '../utils/createPullRequestContext';
import { autoMergeIfPossible } from './autoMergeIfPossible';
import { editOpenedPR } from './editOpenedPR';
import { updateBranch } from './updateBranch';
import { updatePrCommentBodyIfNeeded } from './updatePrCommentBody';
import type { Options } from './utils/body/prOptions';
import { updateStatusCheckFromLabels } from './updateStatusCheckFromLabels';
import { calcDefaultOptions } from './utils/body/prOptions';
import { updateCommentOptions } from './utils/body/updateBody';
import hasLabelInPR from './utils/hasLabelInPR';
import syncLabel from './utils/syncLabel';

export const calcDefaultOptions = (
repoContext: RepoContext,
pullRequest: PullRequestWithDecentData,
): Options => {
const automergeLabel = repoContext.labels['merge/automerge'];
const skipCiLabel = repoContext.labels['merge/skip-ci'];

const prHasSkipCiLabel = hasLabelInPR(pullRequest.labels, skipCiLabel);
const prHasAutoMergeLabel = hasLabelInPR(pullRequest.labels, automergeLabel);

return {
...repoContext.config.prDefaultOptions,
autoMergeWithSkipCi: prHasSkipCiLabel,
autoMerge: prHasAutoMergeLabel,
};
};

export const syncLabelsAfterCommentBodyEdited = async <
Name extends EventsWithRepository,
>(
export const commentBodyEdited = async <Name extends EventsWithRepository>(
pullRequest: PullRequestFromRestEndpoint,
context: ProbotEvent<Name>,
appContext: AppContext,
repoContext: RepoContext,
reviewflowPrContext: ReviewflowPrContext,
): Promise<void> => {
Expand All @@ -43,7 +26,7 @@ export const syncLabelsAfterCommentBodyEdited = async <
const prHasSkipCiLabel = hasLabelInPR(pullRequest.labels, skipCiLabel);
const prHasAutoMergeLabel = hasLabelInPR(pullRequest.labels, automergeLabel);

const { commentBody, options } = updateCommentOptions(
const { commentBody, options, actions } = updateCommentOptions(
context.payload.repository.html_url,
repoContext.config.labels.list,
reviewflowPrContext.commentBody,
Expand All @@ -62,6 +45,28 @@ export const syncLabelsAfterCommentBodyEdited = async <
skipCiLabel,
prHasSkipCiLabel,
),

actions.includes('updateBranch') &&
updateBranch(pullRequest, context, context.payload.sender.login),
actions.includes('updateChecks') &&
Promise.all([
editOpenedPR(
pullRequest,
context,
appContext,
repoContext,
reviewflowPrContext,
true,
),
updateStatusCheckFromLabels(
pullRequest,
context,
appContext,
repoContext,
reviewflowPrContext,
pullRequest.labels,
),
]),
automergeLabel &&
syncLabel(
pullRequest,
Expand Down
2 changes: 1 addition & 1 deletion src/events/pr-handlers/actions/editOpenedPR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import type { PullRequestWithDecentData } from '../utils/PullRequestData';
import type { ReviewflowPrContext } from '../utils/createPullRequestContext';
import { checkIfUserIsBot } from '../utils/isBotUser';
import { readCommitsAndUpdateInfos } from './readCommitsAndUpdateInfos';
import { calcDefaultOptions } from './syncLabelsAfterCommentBodyEdited';
import { updatePrIfNeeded } from './updatePr';
import { updatePrCommentBodyIfNeeded } from './updatePrCommentBody';
import { calcDefaultOptions } from './utils/body/prOptions';
import {
updateCommentBodyInfos,
defaultCommentBody,
Expand Down
15 changes: 8 additions & 7 deletions src/events/pr-handlers/actions/updateBranch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const updateBranch = async <Name extends EmitterWebhookEventName>(
'update branch result',
);

if (result.status === 204) {
if (result.status === 204 || result.error?.status === 204) {
context.octokit.issues.createComment(
context.repo({
issue_number: pullRequest.number,
Expand All @@ -43,7 +43,7 @@ export const updateBranch = async <Name extends EmitterWebhookEventName>(
}),
);
return true;
} else if (result.status === 409) {
} else if (result.status === 409 || result.error?.status === 409) {
context.octokit.issues.createComment(
context.repo({
issue_number: pullRequest.number,
Expand All @@ -57,11 +57,12 @@ export const updateBranch = async <Name extends EmitterWebhookEventName>(
context.octokit.issues.createComment(
context.repo({
issue_number: pullRequest.number,
body: `${
login ? `@${login} ` : ''
}Could not update branch (unknown error${
result.status ? `, status = ${result.status}` : ''
}).`,
body: `${login ? `@${login} ` : ''}Could not update branch ${
result?.error?.response?.data?.message ??
`(unknown error${
result?.error.status ? `, status = ${result.error.status}` : ''
})`
}.`,
}),
);
return false;
Expand Down
7 changes: 3 additions & 4 deletions src/events/pr-handlers/actions/updateStatusCheckFromLabels.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AppContext } from 'context/AppContext';
import type { RepoContext } from 'context/repoContext';
import type { EventsWithRepository, RepoContext } from 'context/repoContext';
import type { ProbotEvent } from 'events/probot-types';
import type { StatusInfo } from '../../../accountConfigs/types';
import { ExcludesFalsy } from '../../../utils/Excludes';
Expand All @@ -8,10 +8,9 @@ import type {
PullRequestWithDecentData,
} from '../utils/PullRequestData';
import type { ReviewflowPrContext } from '../utils/createPullRequestContext';
import type { EventsWithPullRequest } from '../utils/createPullRequestHandler';
import createStatus, { isSameStatus } from './utils/createStatus';

const addStatusCheck = async function <EventName extends EventsWithPullRequest>(
const addStatusCheck = async function <EventName extends EventsWithRepository>(
pullRequest: PullRequestWithDecentData,
context: ProbotEvent<EventName>,
appContext: AppContext,
Expand Down Expand Up @@ -98,7 +97,7 @@ const addStatusCheck = async function <EventName extends EventsWithPullRequest>(
};

export const updateStatusCheckFromLabels = <
EventName extends EventsWithPullRequest,
EventName extends EventsWithRepository,
>(
pullRequest: PullRequestWithDecentData,
context: ProbotEvent<EventName>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export default `
- [ ] <!-- reviewflow-autoMergeWithSkipCi -->Add \`[skip ci]\` on merge commit
- [ ] <!-- 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)
- [x] <!-- reviewflow-deleteAfterMerge -->Automatic branch delete after this PR is merged
### Actions:
- [ ] <!-- reviewflow-updateChecks -->:bug: Force updating reviewflow checks for this PR. Use this to try to fix reviewflow checks that are still missing/pending, which might happen if webhook failed or something bad happened when reviewflow tried to send the status check to github.
- [ ] <!-- reviewflow-updateBranch -->[:arrows_counterclockwise: update branch](https://github.com/christophehurpeau/reviewflow/labels/%3Aarrows_counterclockwise%3A%20update%20branch): Merge base branch in this PR's branch. Only works if merging is possible without conflicts.
`.trim();

// [ONK-0000](https://a;dlkas;dlkas;dk)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Some informations here, like links.
- [ ] <!-- reviewflow-autoMergeWithSkipCi -->Add \`[skip ci]\` on merge commit
- [ ] <!-- 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)
- [x] <!-- reviewflow-deleteAfterMerge -->Automatic branch delete after this PR is merged
### Actions:
- [ ] <!-- reviewflow-updateChecks -->:bug: Force updating reviewflow checks for this PR. Use this to try to fix reviewflow checks that are still missing/pending, which might happen if webhook failed or something bad happened when reviewflow tried to send the status check to github.
- [ ] <!-- reviewflow-updateBranch -->[:arrows_counterclockwise: update branch](https://github.com/christophehurpeau/reviewflow/labels/%3Aarrows_counterclockwise%3A%20update%20branch): Merge base branch in this PR's branch. Only works if merging is possible without conflicts.
`.trim();

// [ONK-0000](https://a;dlkas;dlkas;dk)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export default `
- [ ] <!-- reviewflow-autoMergeWithSkipCi -->Add \`[skip ci]\` on merge commit
- [ ] <!-- 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)
- [x] <!-- reviewflow-deleteAfterMerge -->Automatic branch delete after this PR is merged
### Actions:
- [ ] <!-- reviewflow-updateChecks -->:bug: Force updating reviewflow checks for this PR. Use this to try to fix reviewflow checks that are still missing/pending, which might happen if webhook failed or something bad happened when reviewflow tried to send the status check to github.
- [ ] <!-- reviewflow-updateBranch -->[:arrows_counterclockwise: update branch](https://github.com/christophehurpeau/reviewflow/labels/%3Aarrows_counterclockwise%3A%20update%20branch): Merge base branch in this PR's branch. Only works if merging is possible without conflicts.
`.trim();

// [ONK-0000](https://a;dlkas;dlkas;dk)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ export default `
- [ ] <!-- reviewflow-autoMerge -->[:vertical_traffic_light: automerge](https://github.com/christophehurpeau/reviewflow/labels/%3Avertical_traffic_light%3A%20automerge): Automatically merge when this PR is ready and has no failed statuses. When the repository requires _branches to be up to date before merging_, it merges default branch, with a queue per repo to prevent multiple merges when several PRs are ready. A fail job prevents the merge.
- [ ] <!-- reviewflow-autoMergeWithSkipCi -->[:vertical_traffic_light: skip-ci](https://github.com/christophehurpeau/reviewflow/labels/%3Avertical_traffic_light%3A%20skip-ci): Add \`[skip ci]\` on merge commit when merge is done with autoMerge.
- [x] <!-- reviewflow-deleteAfterMerge -->:recycle: Automatically delete the branch after this PR is merged.
### Actions:
- [ ] <!-- reviewflow-updateChecks -->:bug: Force updating reviewflow checks for this PR. Use this to try to fix reviewflow checks that are still missing/pending, which might happen if webhook failed or something bad happened when reviewflow tried to send the status check to github.
- [ ] <!-- reviewflow-updateBranch -->[:arrows_counterclockwise: update branch](https://github.com/christophehurpeau/reviewflow/labels/%3Aarrows_counterclockwise%3A%20update%20branch): Merge base branch in this PR's branch. Only works if merging is possible without conflicts.
`.trim();

// [ONK-0000](https://a;dlkas;dlkas;dk)
15 changes: 15 additions & 0 deletions src/events/pr-handlers/actions/utils/body/parseBody.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ActionKeys } from './prActions';
import { actionRegexps } from './prActions';
import { optionsRegexps } from './prOptions';
import type { Options } from './prOptions';

Expand All @@ -19,6 +21,19 @@ export const parseOptions = (
return options as Options;
};

export const parseActions = (content: string): ActionKeys[] => {
const actions: ActionKeys[] = [];

actionRegexps.forEach(({ key, regexp }) => {
const match = regexp.exec(content);
if (match && (match[1] === 'x' || match[1] === 'X')) {
actions.push(key);
}
});

return actions;
};

export const parseCommitNotes = (content: string): string => {
const commitNotes = content.replace(
/^.*####? Commits Notes:(.*)####? Options:.*$/s,
Expand Down
32 changes: 32 additions & 0 deletions src/events/pr-handlers/actions/utils/body/prActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export type ActionKeys = 'updateChecks' | 'updateBranch';

export const actions: ActionKeys[] = ['updateChecks', 'updateBranch'];
export const actionRegexps: {
key: ActionKeys;
regexp: RegExp;
}[] = actions.map((action) => ({
key: action,
regexp: new RegExp(`\\[([ xX]?)]\\s*<!-- reviewflow-${action} -->`),
}));

interface ActionDisplay {
key: ActionKeys;
labelKey?: string;
icon?: string;
description: string;
}

export const actionDescriptions: ActionDisplay[] = [
{
key: 'updateChecks',
icon: ':bug:',
description:
'Force updating reviewflow checks for this PR. Use this to try to fix reviewflow checks that are still missing/pending, which might happen if webhook failed or something bad happened when reviewflow tried to send the status check to github.',
},
{
key: 'updateBranch',
labelKey: 'merge/update-branch',
description:
"Merge base branch in this PR's branch. Only works if merging is possible without conflicts.",
},
];
21 changes: 21 additions & 0 deletions src/events/pr-handlers/actions/utils/body/prOptions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import type { RepoContext } from 'context/repoContext';
import type { PullRequestWithDecentData } from 'events/pr-handlers/utils/PullRequestData';
import hasLabelInPR from '../hasLabelInPR';

export type OptionsKeys =
| 'autoMerge'
| 'autoMergeWithSkipCi'
Expand Down Expand Up @@ -44,3 +48,20 @@ export const optionsDescriptions: OptionDisplay[] = [
description: 'Automatically delete the branch after this PR is merged.',
},
];

export const calcDefaultOptions = (
repoContext: RepoContext,
pullRequest: PullRequestWithDecentData,
): Options => {
const automergeLabel = repoContext.labels['merge/automerge'];
const skipCiLabel = repoContext.labels['merge/skip-ci'];

const prHasSkipCiLabel = hasLabelInPR(pullRequest.labels, skipCiLabel);
const prHasAutoMergeLabel = hasLabelInPR(pullRequest.labels, automergeLabel);

return {
...repoContext.config.prDefaultOptions,
autoMergeWithSkipCi: prHasSkipCiLabel,
autoMerge: prHasAutoMergeLabel,
};
};
30 changes: 28 additions & 2 deletions src/events/pr-handlers/actions/utils/body/updateBody.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { LabelList, StatusInfo } from 'accountConfigs/types';
import type { Options } from './parseBody';
import { parseOptions } from './parseBody';
import { parseActions, parseOptions } from './parseBody';
import type { ActionKeys } from './prActions';
import { actionDescriptions } from './prActions';
import { optionsDescriptions } from './prOptions';

export const defaultCommentBody = 'This will be auto filled by reviewflow.';
Expand Down Expand Up @@ -29,6 +31,28 @@ const toMarkdownOptions = (
.join('\n');
};

const toMarkdownActions = (
repoLink: string,
labelsConfig: LabelList,
): string => {
return actionDescriptions
.map(({ key, labelKey, description, icon: iconValue }) => {
// should always update without ticking the box
const checkboxWithId = `[ ] <!-- reviewflow-${key} -->`;

const labelDescription = labelKey && labelsConfig[labelKey];
const labelLink = labelDescription
? `[${labelDescription.name}](${repoLink}/labels/${encodeURIComponent(
labelDescription.name,
)}): `
: '';
const icon = labelLink || !iconValue ? '' : `${iconValue} `;

return `- ${checkboxWithId}${icon}${labelLink}${description}`;
})
.join('\n');
};

const toMarkdownInfos = (infos: StatusInfo[]): string => {
return infos
.map((info) => {
Expand All @@ -41,6 +65,7 @@ const toMarkdownInfos = (infos: StatusInfo[]): string => {
interface UpdatedBodyWithOptions {
commentBody: string;
options?: Options;
actions: ActionKeys[];
}

const getInfosReplacement = (infos?: StatusInfo[]): string => {
Expand Down Expand Up @@ -75,7 +100,7 @@ const internalUpdateBodyOptionsAndInfos = (
repoLink,
labelsConfig,
options,
)}`;
)}\n### Actions:\n${toMarkdownActions(repoLink, labelsConfig)}`;
};

export const createCommentBody = (
Expand Down Expand Up @@ -105,6 +130,7 @@ export const updateCommentOptions = (

return {
options: updatedOptions,
actions: parseActions(commentBody),
commentBody: internalUpdateBodyOptionsAndInfos(
repoLink,
labelsConfig,
Expand Down
5 changes: 3 additions & 2 deletions src/events/pr-handlers/commentEditedOrDeleted.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Probot } from 'probot';
import type { AppContext } from '../../context/AppContext';
import { syncLabelsAfterCommentBodyEdited } from './actions/syncLabelsAfterCommentBodyEdited';
import { commentBodyEdited } from './actions/commentBodyEdited';
import { createPullRequestHandler } from './utils/createPullRequestHandler';
import { createMrkdwnSectionBlock } from './utils/createSlackMessageWithSecondaryBlock';
import { fetchPr } from './utils/fetchPr';
Expand Down Expand Up @@ -50,9 +50,10 @@ export default function prCommentEditedOrDeleted(
) {
const updatedPr = await fetchPr(context, pullRequest.number);
if (!updatedPr.closed_at) {
await syncLabelsAfterCommentBodyEdited(
await commentBodyEdited(
updatedPr,
context,
appContext,
repoContext,
reviewflowPrContext,
);
Expand Down

0 comments on commit a49fdef

Please sign in to comment.