From 1f3fb9383bae104a5e3d1154947c728ab5377d47 Mon Sep 17 00:00:00 2001 From: Teodorus Nathaniel <53143942+teodorus-nathaniel@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:18:50 +0700 Subject: [PATCH] feat: send bug report warning comment (#317) * 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 --- src/lib/server/trigger-dev/jobs/check-run.ts | 148 ++++++++++-------- .../server/trigger-dev/jobs/issues-comment.ts | 7 +- .../trigger-dev/jobs/issues-creation.ts | 1 + src/lib/server/trigger-dev/utils.ts | 73 +++++++-- 4 files changed, 144 insertions(+), 85 deletions(-) diff --git a/src/lib/server/trigger-dev/jobs/check-run.ts b/src/lib/server/trigger-dev/jobs/check-run.ts index e1f1363..f019a17 100644 --- a/src/lib/server/trigger-dev/jobs/check-run.ts +++ b/src/lib/server/trigger-dev/jobs/check-run.ts @@ -22,7 +22,11 @@ import { githubApp, bugCheckPrefix, submissionHeaderComment, - bodyWithHeader + bodyWithHeader, + reinsertComment, + deleteComment, + getPreviousComment, + createComment } from '../utils'; export async function createJob>( @@ -255,15 +259,16 @@ async function runSubmissionJob 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( - { 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; @@ -333,6 +338,7 @@ async function runSubmissionJob>( payload: EventSchema, io: T @@ -374,18 +380,48 @@ async function runBugReportJob { - 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( - { 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 () => { @@ -415,61 +451,37 @@ async function runBugReportJob( - 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( diff --git a/src/lib/server/trigger-dev/jobs/issues-comment.ts b/src/lib/server/trigger-dev/jobs/issues-comment.ts index c7fbfa7..dcc5129 100644 --- a/src/lib/server/trigger-dev/jobs/issues-comment.ts +++ b/src/lib/server/trigger-dev/jobs/issues-comment.ts @@ -7,7 +7,8 @@ import { submissionHeaderComment, getPullRequestByIssue, excludedAccounts, - reinsertComment + reinsertComment, + runPrFixCheckRun } from '../utils'; export async function createJob>( @@ -53,7 +54,7 @@ export async function createJob, - 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', @@ -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 ``; } - -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 ( repo: { owner: string; repo: string }, idNumber: number, - category: string, + category: PreviousCommentCategory, h: string, + senderFilter: PreviousCommentSenderFilter, octokit: T ) => { let after = null; @@ -360,12 +398,14 @@ const queryPreviousComment = async ( // 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; } @@ -382,7 +422,8 @@ async function getPreviousComment( repositoryName: string, header: string, issueNumber: number, - category: string, + category: PreviousCommentCategory, + senderFilter: PreviousCommentSenderFilter, io: any ): Promise { const previousComment = await io.runTask('get-previous-comment', async () => { @@ -393,6 +434,7 @@ async function getPreviousComment( issueNumber, category, header, + senderFilter, octokit ); return previous; @@ -432,7 +474,7 @@ async function getPullRequestByIssue( orgName: string, repositoryName: string, io: any -): Promise { +): Promise { const previousComment = await io.runTask('get-pull-request-by-issue', async () => { try { const octokit = await githubApp.getInstallationOctokit(orgID); @@ -467,6 +509,7 @@ async function reinsertComment