Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Blame #778

Open
wants to merge 7 commits into
base: development
Choose a base branch
from
Open

Blame #778

Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/handlers/comment/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import {
getTokenSymbol,
getAllIssueAssignEvents,
calculateWeight,
getAllPullRequests,
} from "../../../helpers";
import { getBotConfig, getBotContext, getLogger } from "../../../bindings";
import { handleIssueClosed } from "../../payout";
import { query } from "./query";
import { autoPay } from "./payout";
import { getTargetPriceLabel } from "../../shared";
import { ErrorDiff } from "../../../utils/helpers";
import { lastActivityTime } from "../../wildcard";

export * from "./assign";
export * from "./wallet";
Expand Down Expand Up @@ -117,6 +119,119 @@ export const issueCreatedCallback = async (): Promise<void> => {
}
};

/**
* Callback for issues reopened - Blame Processor
* @notice Identifies the changes in main that broke the features of the issue
* @notice This is to assign responsibility to the person who broke the feature
* @dev The person in fault will be penalized...
*/
export const issueReopenedBlameCallback = async (): Promise<void> => {
const logger = getLogger();
const context = getBotContext();
// const config = getBotConfig();
const payload = context.payload as Payload;
const issue = payload.issue;
const repository = payload.repository;

if (!issue) return;
if (!repository) return;

const allRepoCommits = await context.octokit.repos
.listCommits({
owner: repository.owner.login,
repo: repository.name,
})
.then((res) => res.data);

const currentCommit = allRepoCommits[0];
const currentCommitSha = currentCommit.sha;
const lastActivity = await lastActivityTime(issue, await getAllIssueComments(issue.number));

const allClosedPulls = await getAllPullRequests(context, "closed");
const mergedPulls = allClosedPulls.filter((pull) => pull.merged_at && pull.merged_at > lastActivity.toISOString());
const mergedSHAs = mergedPulls.map((pull) => pull.merge_commit_sha);
const commitsThatMatch = allRepoCommits.filter((commit) => mergedSHAs.includes(commit.sha)).reverse();

const pullsThatCommitsMatch = await Promise.all(
commitsThatMatch.map((commit) =>
context.octokit.repos
.listPullRequestsAssociatedWithCommit({
owner: repository.owner.login,
repo: repository.name,
commit_sha: commit.sha,
})
.then((res) => res.data)
)
);

// it looks like [[16],[48]] so we need to flatten it not using flat()
const onlyPRsNeeded = pullsThatCommitsMatch.map((pulls) => pulls.map((pull) => pull.number)).reduce((acc, val) => acc.concat(val), []);

const issueRegex = new RegExp(`#${issue.number}`, "g");
const matchingPull = mergedPulls.find((pull) => pull.body?.match(issueRegex));

if (!matchingPull) {
logger.info(`No matching pull found for issue #${issue.number}`);
return;
}

const pullDiff = await context.octokit.repos
.compareCommitsWithBasehead({
owner: repository.owner.login,
repo: repository.name,
basehead: matchingPull?.merge_commit_sha + "..." + currentCommitSha,
mediaType: {
format: "diff",
},
})
.then((res) => res.data);

const diffs = [];
const fileLens: number[] = [];

for (const sha of mergedSHAs) {
if (!sha) continue;
const diff = await context.octokit.repos
.compareCommitsWithBasehead({
owner: repository.owner.login,
repo: repository.name,
basehead: sha + "..." + currentCommitSha,
})
.then((res) => res.data);

const fileLen = diff.files?.length;

fileLens.push(fileLen || 0);
diffs.push(diff);

if (diff.files && diff.files.length > 0) {
logger.info(`Found ${diff.files.length} files changed in commit ${sha}`);
} else {
logger.info(`No files changed in commit ${sha}`);
}
}

if (pullDiff.files && pullDiff.files.length > 0) {
logger.info(`Found ${pullDiff.files.length} files changed in commit ${matchingPull?.merge_commit_sha}`);
}

const comment = `
The following pull requests were merged after this issue was closed:
${onlyPRsNeeded
.sort()
.map((pullNumber) => `<ul><li>#${pullNumber}</li></ul>`)
.join("\n")}

| **Files Changed** | **Commit** | **Author** |
| --- | --- | --- |
${onlyPRsNeeded.map((_pullNumber, index) => `| ${fileLens[index]} | ${commitsThatMatch[index].sha} | ${commitsThatMatch[index].author?.login} |`).join("\n")}

Basehead Comparison: ${matchingPull?.merge_commit_sha}...${currentCommitSha}
`;

await addCommentToIssue(comment, issue.number);
};

/**
* Callback for issues reopened - Processor
*/
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { closePullRequestForAnIssue, commentWithAssignMessage } from "./assign";
import { pricingLabelLogic, validatePriceLabels } from "./pricing";
import { checkBountiesToUnassign, collectAnalytics, checkWeeklyUpdate } from "./wildcard";
import { nullHandler } from "./shared";
import { handleComment, issueClosedCallback, issueCreatedCallback, issueReopenedCallback } from "./comment";
import { handleComment, issueClosedCallback, issueCreatedCallback, issueReopenedBlameCallback, issueReopenedCallback } from "./comment";
import { checkPullRequests } from "./assign/auto";
import { createDevPoolPR } from "./pull-request";
import { incentivizeComments, incentivizeCreatorComment, incentivizePullRequestReviews } from "./payout";
Expand All @@ -18,7 +18,7 @@ export const processors: Record<string, Handler> = {
},
[GithubEvent.ISSUES_REOPENED]: {
pre: [nullHandler],
action: [issueReopenedCallback],
action: [issueReopenedBlameCallback, issueReopenedCallback],
post: [nullHandler],
0x4007 marked this conversation as resolved.
Show resolved Hide resolved
},
[GithubEvent.ISSUES_LABELED]: {
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/wildcard/unassign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const checkBountyToUnassign = async (issue: Issue): Promise<boolean> => {
return false;
};

const lastActivityTime = async (issue: Issue, comments: Comment[]): Promise<Date> => {
export const lastActivityTime = async (issue: Issue, comments: Comment[]): Promise<Date> => {
const logger = getLogger();
logger.info(`Checking the latest activity for the issue, issue_number: ${issue.number}`);
const assignees = issue.assignees.map((i) => i.login);
Expand Down