Skip to content

Commit

Permalink
feat: delete bug fix check and warning message after edit pr title (#319
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

* feat: add logic to delete fix pr check if pr title updated

* feat: add delete check run

* fix: wrong logic

* feat: update check run status to neutral

* refactor: rename task name and remove unnecessary task

* chore: remove console log

* chore: remove comment instead use dummy selection

* refactor: extract `add pr fix warning` functionality

* refactor: remove unused imports
  • Loading branch information
teodorus-nathaniel authored Nov 15, 2024
1 parent 1f3fb93 commit 70ce3b8
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 60 deletions.
28 changes: 3 additions & 25 deletions src/lib/server/trigger-dev/jobs/check-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ import type { TriggerContext, IOWithIntegrations } from '@trigger.dev/sdk';
import type { Autoinvoicing } from '@holdex/autoinvoicing';
import type { Octokit } from 'octokit';
import type {
User,
Repository,
IssueComment,
CheckRun,
PullRequestConnection,
PullRequest,
UpdateCheckRunPayload,
UpdateCheckRunInput
PullRequest
} from '@octokit/graphql-schema';
import type { CheckRunEvent } from '@octokit/webhooks-types';

Expand All @@ -26,7 +22,8 @@ import {
reinsertComment,
deleteComment,
getPreviousComment,
createComment
createComment,
updateCheckRun
} from '../utils';

export async function createJob<T extends IOWithIntegrations<{ github: Autoinvoicing }>>(
Expand Down Expand Up @@ -571,25 +568,6 @@ async function getPrInfoByCheckRunNodeId<T extends Octokit>(
return ((commit.associatedPullRequests as PullRequestConnection).nodes as PullRequest[])[0];
}

async function updateCheckRun<T extends Octokit>(octokit: T, input: UpdateCheckRunInput) {
return octokit.graphql<{ updateCheckRun: UpdateCheckRunPayload }>(
`
mutation($input: UpdateCheckRunInput!) {
updateCheckRun(input: $input) {
checkRun {
id
conclusion
title
summary
}
clientMutationId
}
}
`,
{ input }
);
}

const regex = new RegExp(/\B@([a-z0-9](?:-(?=[a-z0-9])|[a-z0-9]){0,38}(?<=[a-z0-9]))/, 'gmi');
function bindMembers(previousCommentBody: string, member: string, submissionCreated: boolean) {
if (previousCommentBody.length === 0) {
Expand Down
233 changes: 198 additions & 35 deletions src/lib/server/trigger-dev/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import type {
User as UserGQL,
Repository as RepoGQL,
IssueComment,
PullRequest as PullRequestGQL
UpdateCheckRunInput,
UpdateCheckRunPayload
} from '@octokit/graphql-schema';
import type { ContributorSchema, ItemSchema } from '$lib/@types';
import type { IOWithIntegrations } from '@trigger.dev/sdk';
Expand Down Expand Up @@ -174,6 +175,104 @@ const createCheckRunIfNotExists = async (
}
};

async function updateCheckRun<T extends Octokit>(octokit: T, input: UpdateCheckRunInput) {
return octokit.graphql<{ updateCheckRun: UpdateCheckRunPayload }>(
`
mutation($input: UpdateCheckRunInput!) {
updateCheckRun(input: $input) {
checkRun {
id
conclusion
title
summary
}
clientMutationId
}
}
`,
{ input }
);
}

const deleteCheckRun = async (
org: { name: string; installationId: number; repo: string },
sender: { login: string; id: number },
pull_request: PullRequest | SimplePullRequest,
checkName: (s: string) => string,
io: any
) => {
return await io.runTask('delete-check-run', async () => {
const checkRunId = await io.runTask('get-check-run-id', async () => {
const octokit = await githubApp.getInstallationOctokit(org.installationId);

const { data } = await octokit.rest.checks
.listForRef({
owner: org.name,
repo: org.repo,
ref: pull_request.head.sha,
check_name: checkName(sender.login)
})
.catch(() => ({
data: {
total_count: 0,
check_runs: []
}
}));

if (data.total_count === 0) {
return null;
}
return data.check_runs[data.total_count - 1].id;
});

if (checkRunId) {
const repoDetails = await io.runTask(
'get-repo-id',
async () => {
const octokit = await githubApp.getInstallationOctokit(org.installationId);

return octokit.rest.repos.get({ owner: org.name, repo: org.repo });
},
{ name: 'Get Repo Details' }
);

const checkDetails = await io.runTask(
'get-check-id',
async () => {
const octokit = await githubApp.getInstallationOctokit(org.installationId);
return octokit.rest.checks.get({
owner: org.name,
repo: org.repo,
check_run_id: checkRunId
});
},
{ name: 'Get Check Details' }
);

await io.runTask(
'update-check-run-to-completed',
async () => {
const octokit = await githubApp.getInstallationOctokit(org.installationId);

return updateCheckRun(octokit, {
repositoryId: repoDetails.data.node_id,
checkRunId: checkDetails.data.node_id,
status: 'COMPLETED',
conclusion: 'NEUTRAL',
completedAt: new Date().toISOString(),
detailsUrl: `https://pr-time-tracker.vercel.app/prs/${org.name}/${repoDetails.data.name}/${pull_request.id}`,
output: {
title: '⚪ bug info check cancelled',
summary: 'Pull request title no longer includes `fix:`. No further actions required'
}
}).then((r) => r.updateCheckRun);
},
{ name: 'Update check run' }
);
}
});
};

const reRequestCheckRun = async (
org: { name: string; installationId: number },
repoName: string,
Expand Down Expand Up @@ -241,58 +340,70 @@ const checkRunFromEvent = async (
);
};

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

// TODO: remove this when the feature is ready
const isTitleChangedFromFixPr =
payload.action === 'edited' &&
'title' in payload.changes &&
fixPrRegex.test(payload.changes.title?.from ?? '') &&
!fixPrRegex.test(title);
const isFixPr = fixPrRegex.test(title);

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

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;
if (!isFixPr && !isTitleChangedFromFixPr) {
return;
}

let pullRequest: SimplePullRequest | PullRequest;
if ('pull_request' in payload) {
pullRequest = 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');
}
pullRequest = pr;
}

const { user } = pull_request;
const orgDetails = await io.runTask(
'get org installation',
async () => {
const { data } = await getInstallationId(organization?.login as string);
return data;
},
{ name: 'Get Organization installation' }
);

const orgDetails = await io.runTask(
'get org installation',
async () => {
const { data } = await getInstallationId(organization?.login as string);
return data;
},
{ name: 'Get Organization installation' }
);
if (isFixPr) {
const { user } = pullRequest;

await io.runTask(
`create-check-run-for-fix-pr`,
Expand All @@ -304,7 +415,7 @@ async function runPrFixCheckRun<
repo: repository.name
},
user,
pull_request,
pullRequest,
(b) => bugCheckName(b),
'bug_report'
);
Expand All @@ -313,9 +424,59 @@ async function runPrFixCheckRun<
},
{ name: `check run for fix PR` }
);
} else if (isTitleChangedFromFixPr) {
if (!payload.organization) {
return io.logger.log('organization not found');
}

await deleteFixPrReportAndResolveCheckRun(
orgDetails.id,
payload.organization.login,
repository.name,
pullRequest,
sender,
io
);
}
}

async function deleteFixPrReportAndResolveCheckRun(
orgID: number,
orgName: string,
repositoryName: string,
pullRequest: SimplePullRequest | PullRequest,
sender: { login: string; id: number },
io: any
) {
await io.runTask(
`delete-fix-pr-warning-and-resolve-check-run`,
async () => {
const previousBugReportWarning = await getPreviousComment(
orgID,
orgName,
repositoryName,
submissionHeaderComment('Bug Report', pullRequest.number.toString()),
pullRequest.number,
'pullRequest',
'bot',
io
);
if (previousBugReportWarning) {
await deleteComment(orgID, orgName, repositoryName, previousBugReportWarning, io);
}

await deleteCheckRun(
{ name: orgName, installationId: orgID, repo: repositoryName },
sender,
pullRequest,
(s) => bugCheckName(s),
io
);
},
{ name: `delete fix pr warning and resolve check run` }
);
}

async function deleteComment(
orgID: number,
orgName: string,
Expand Down Expand Up @@ -537,6 +698,8 @@ export {
createCheckRunIfNotExists,
getContributorInfo,
checkRunFromEvent,
updateCheckRun,
deleteCheckRun,
getPrInfo,
getSubmissionStatus,
bugCheckName,
Expand Down

0 comments on commit 70ce3b8

Please sign in to comment.