Skip to content

Commit

Permalink
feat: send bug report warning comment (#317)
Browse files Browse the repository at this point in the history
* feat: add sender filter for getting previous comment

* fix: add new params for getPreviousComment

* feat: send bug report warning on every run check

* feat: run fix pr check on issue comment

* chore: remove console log

* chore: remove comment instead use dummy selection

* refactor: extract `add pr fix warning` functionality

* refactor: remove unnecessary variables

* refactor: remove unnecessary variable
  • Loading branch information
teodorus-nathaniel authored Nov 14, 2024
1 parent c7bfd69 commit 1f3fb93
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 85 deletions.
148 changes: 80 additions & 68 deletions src/lib/server/trigger-dev/jobs/check-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import {
githubApp,
bugCheckPrefix,
submissionHeaderComment,
bodyWithHeader
bodyWithHeader,
reinsertComment,
deleteComment,
getPreviousComment,
createComment
} from '../utils';

export async function createJob<T extends IOWithIntegrations<{ github: Autoinvoicing }>>(
Expand Down Expand Up @@ -255,15 +259,16 @@ async function runSubmissionJob<T extends IOWithIntegrations<{ github: Autoinvoi
// if success -> check comment -> create if not exits -> update the list

const previous = await io.runTask('get previous comment', async () => {
const octokit = await githubApp.getInstallationOctokit(orgDetails.id);

const previous = await getPreviousComment<typeof octokit>(
{ owner: payload.organization, repo: repoDetails.data.name },
payload.prNumber,
return await getPreviousComment(
orgDetails.id,
payload.organization,
payload.repo,
submissionHeaderComment('Pull Request', payload.prId.toString()),
octokit
payload.prNumber,
'pullRequest',
'bot',
io
);
return previous;
});
let current: any = null;

Expand Down Expand Up @@ -333,6 +338,7 @@ async function runSubmissionJob<T extends IOWithIntegrations<{ github: Autoinvoi
}
}

const bugReportPrefix = '@pr-time-tracker bug commit';
async function runBugReportJob<T extends IOWithIntegrations<{ github: Autoinvoicing }>>(
payload: EventSchema,
io: T
Expand Down Expand Up @@ -374,18 +380,48 @@ async function runBugReportJob<T extends IOWithIntegrations<{ github: Autoinvoic
{ name: 'Get Check Details' }
);

const bugReportComment = await io.runTask('get report comment', async () => {
const octokit = await githubApp.getInstallationOctokit(orgDetails.id);
const bugReportComment = await io.runTask('get-report-comment', async () => {
return await getPreviousComment(
orgDetails.id,
payload.organization,
payload.repo,
bugReportPrefix,
payload.prNumber,
'pullRequest',
'others',
io
);
});

const previous = await getPreviousComment<typeof octokit>(
{ owner: payload.organization, repo: repoDetails.data.name },
const previousBugReportWarning = await io.runTask('get-previous-bug-report-warning', async () => {
return await getPreviousComment(
orgDetails.id,
payload.organization,
payload.repo,
submissionHeaderComment('Bug Report', payload.prNumber.toString()),
payload.prNumber,
`@pr-time-tracker bug commit`,
octokit
'pullRequest',
'bot',
io
);
return previous;
});

if (!bugReportComment) {
await addBugReportWarning(previousBugReportWarning, orgDetails, payload, io);
} else {
if (previousBugReportWarning) {
await io.runTask('delete-bug-report-warning', async () => {
await deleteComment(
orgDetails.id,
payload.organization,
payload.repo,
previousBugReportWarning,
io
);
});
}
}

await io.runTask(
'update-report-check-run',
async () => {
Expand Down Expand Up @@ -415,61 +451,37 @@ async function runBugReportJob<T extends IOWithIntegrations<{ github: Autoinvoic
// }
}

async function getPreviousComment<T extends Octokit>(
repo: { owner: string; repo: string },
prNumber: number,
h: string,
octokit: T
async function addBugReportWarning(
previousBugReportWarning: IssueComment | undefined,
orgDetails: { id: number },
payload: EventSchema,
io: any
) {
let after = null;
let hasNextPage = true;

while (hasNextPage) {
/* eslint-disable no-await-in-loop */
const data = await octokit.graphql<{ repository: Repository; viewer: User }>(
`
query($repo: String! $owner: String! $number: Int! $after: String) {
viewer { login }
repository(name: $repo owner: $owner) {
pullRequest(number: $number) {
comments(first: 100 after: $after) {
nodes {
id
databaseId
author {
login
}
isMinimized
body
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
}
`,
{ ...repo, after, number: prNumber }
);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const viewer = data.viewer as User;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const repository = data.repository as Repository;
const target = repository.pullRequest?.comments?.nodes?.find(
(node: IssueComment | null | undefined) =>
node?.author?.login === viewer.login.replace('[bot]', '') &&
!node?.isMinimized &&
node?.body?.includes(h)
);
if (target) {
return target;
return await io.runTask('add-bug-report-warning', async () => {
if (previousBugReportWarning) {
return await reinsertComment(
orgDetails.id,
payload.organization,
payload.repo,
submissionHeaderComment('Bug Report', payload.prNumber.toString()),
payload.prNumber,
io
);
} else {
return await createComment(
orgDetails.id,
payload.organization,
payload.repo,
bodyWithHeader(
'Bug Report',
`@${payload.senderLogin} please use git blame and specify the link to the commit link that has introduced this bug. Send the following message in this PR: \`${bugReportPrefix} [link] && bug author @name\``,
payload.prNumber.toString()
),
payload.prNumber,
io
);
}
after = repository.pullRequest?.comments?.pageInfo?.endCursor;
hasNextPage = repository.pullRequest?.comments?.pageInfo?.hasNextPage ?? false;
}
return undefined;
});
}

async function getPrInfoByCheckRunNodeId<T extends Octokit>(
Expand Down
7 changes: 5 additions & 2 deletions src/lib/server/trigger-dev/jobs/issues-comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
submissionHeaderComment,
getPullRequestByIssue,
excludedAccounts,
reinsertComment
reinsertComment,
runPrFixCheckRun
} from '../utils';

export async function createJob<T extends IOWithIntegrations<{ github: Autoinvoicing }>>(
Expand Down Expand Up @@ -53,14 +54,16 @@ export async function createJob<T extends IOWithIntegrations<{ github: Autoinvoi
orgDetails.id,
org.name,
repository.name,
submissionHeaderComment('Pull Request', pr.id),
submissionHeaderComment('Pull Request', pr.id.toString()),
issue.number,
io
);
},
{ name: 'Reinsert sticky comment' }
);

await runPrFixCheckRun({ ...payload, pull_request: pr }, io);

break;
}
default: {
Expand Down
1 change: 1 addition & 0 deletions src/lib/server/trigger-dev/jobs/issues-creation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export async function createJob<T extends IOWithIntegrations<{ github: Autoinvoi
submissionHeaderComment('Issue', payload.issue.id.toString()),
issue.number,
'issue',
'bot',
io
);

Expand Down
73 changes: 58 additions & 15 deletions src/lib/server/trigger-dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
Repository,
PullRequestEvent,
PullRequestReviewEvent,
Issue
Issue,
IssueCommentEvent
} from '@octokit/webhooks-types';
import type {
User as UserGQL,
Expand Down Expand Up @@ -242,13 +243,47 @@ const checkRunFromEvent = async (

async function runPrFixCheckRun<
T extends IOWithIntegrations<{ github: Autoinvoicing }>,
E extends PullRequestEvent | PullRequestReviewEvent = PullRequestEvent | PullRequestReviewEvent
E extends PullRequestEvent | PullRequestReviewEvent | IssueCommentEvent =
| PullRequestEvent
| PullRequestReviewEvent
| IssueCommentEvent
>(payload: E, io: T) {
const { pull_request, repository, organization } = payload;
const { repository, organization } = payload;
let title;
if ('pull_request' in payload) {
title = payload.pull_request.title;
} else {
title = payload.issue.title;
}

const { title, user } = pull_request;
// TODO: remove this when the feature is ready
const dummy = true;
if (/^fix:/.test(title)) {
return io.logger.log('identified pull request');
if (dummy) {
return io.logger.log('identified pull request');
}

let pull_request: SimplePullRequest | PullRequest;
if ('pull_request' in payload) {
pull_request = payload.pull_request;
} else {
if (!payload.organization) {
return io.logger.log('organization not found');
}
const pr = await getPullRequestByIssue(
payload.issue,
payload.organization?.id,
payload.organization?.login,
payload.repository.name,
io
);
if (!pr) {
return io.logger.log('pull request from issue not found');
}
pull_request = pr;
}

const { user } = pull_request;

const orgDetails = await io.runTask(
'get org installation',
Expand Down Expand Up @@ -307,19 +342,22 @@ async function deleteComment(
}
}

function submissionHeaderComment(type: 'Issue' | 'Pull Request', header: string): string {
type SubmissionHeaderType = 'Issue' | 'Pull Request' | 'Bug Report';
function submissionHeaderComment(type: SubmissionHeaderType, header: string): string {
return `<!-- Sticky ${type} Comment${header} -->`;
}

function bodyWithHeader(type: 'Issue' | 'Pull Request', body: string, header: string): string {
function bodyWithHeader(type: SubmissionHeaderType, body: string, header: string): string {
return `${body}\n${submissionHeaderComment(type, header)}`;
}

type PreviousCommentCategory = 'pullRequest' | 'issue';
type PreviousCommentSenderFilter = 'bot' | 'others';
const queryPreviousComment = async <T extends Octokit>(
repo: { owner: string; repo: string },
idNumber: number,
category: string,
category: PreviousCommentCategory,
h: string,
senderFilter: PreviousCommentSenderFilter,
octokit: T
) => {
let after = null;
Expand Down Expand Up @@ -360,12 +398,14 @@ const queryPreviousComment = async <T extends Octokit>(
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const repository = data.repository as RepoGQL;
const categoryObj = category === 'issue' ? repository.issue : repository.pullRequest;
const target = categoryObj?.comments?.nodes?.find(
(node: IssueComment | null | undefined) =>
node?.author?.login === viewer.login.replace('[bot]', '') &&
const target = categoryObj?.comments?.nodes?.find((node: IssueComment | null | undefined) => {
const isSentByBot = node?.author?.login === viewer.login.replace('[bot]', '');
return (
((senderFilter === 'bot' && isSentByBot) || (senderFilter === 'others' && !isSentByBot)) &&
!node?.isMinimized &&
node?.body?.includes(h)
);
);
});
if (target) {
return target;
}
Expand All @@ -382,7 +422,8 @@ async function getPreviousComment(
repositoryName: string,
header: string,
issueNumber: number,
category: string,
category: PreviousCommentCategory,
senderFilter: PreviousCommentSenderFilter,
io: any
): Promise<IssueComment | undefined> {
const previousComment = await io.runTask('get-previous-comment', async () => {
Expand All @@ -393,6 +434,7 @@ async function getPreviousComment(
issueNumber,
category,
header,
senderFilter,
octokit
);
return previous;
Expand Down Expand Up @@ -432,7 +474,7 @@ async function getPullRequestByIssue(
orgName: string,
repositoryName: string,
io: any
): Promise<PullRequestGQL | undefined> {
): Promise<PullRequest | undefined> {
const previousComment = await io.runTask('get-pull-request-by-issue', async () => {
try {
const octokit = await githubApp.getInstallationOctokit(orgID);
Expand Down Expand Up @@ -467,6 +509,7 @@ async function reinsertComment<T extends IOWithIntegrations<{ github: Autoinvoic
header,
prOrIssueNumber,
'pullRequest',
'bot',
io
);

Expand Down

0 comments on commit 1f3fb93

Please sign in to comment.