Skip to content

Commit

Permalink
[fix] Fix action on comment (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
baseballyama committed Nov 5, 2023
1 parent 226a5c9 commit fa4c2fc
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 46 deletions.
20 changes: 11 additions & 9 deletions packages/ai-craftsman/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ const main = async () => {
}

let isIncremental = false;
if (git.comment) {
if (git.commentId && git.comment) {
await git.reactToComment(git.commentId, "eyes");

if (!git.comment.startsWith("/ai-review-flex")) {
console.log(
"Skip AI review because the comment doesn't starts with /ai-review-flex."
Expand All @@ -69,11 +71,12 @@ const main = async () => {

const rules = await readCodingRules();
const promises: (() => Promise<void>)[] = [];
let commented = false;
const targetBranch = isIncremental
? await git.getLatestCommitIdByTheApp()
: await git.getBaseRef();
for (const { diff, path } of git.getDiff(targetBranch)) {
let commentedCount = 0;
let { base, head } = await git.getRef();
if (isIncremental) {
base = await git.getLatestCommitIdByTheApp();
}
for (const { diff, path } of git.getDiff(base, head)) {
if (excludePatterns.some((pattern) => pattern.test(path))) {
console.log(`SKIP REVIEW: ${path}`);
continue;
Expand Down Expand Up @@ -110,16 +113,15 @@ const main = async () => {
comment.end,
comment.body
);
commented = true;
commentedCount += 1;
}
});
}
}
}

await promiseAllWithConcurrencyLimit(promises, 1);

if (!commented) {
if (commentedCount === 0) {
git.postComment("Great! No problem found by AI Review Flex.");
}
};
Expand Down
1 change: 1 addition & 0 deletions packages/ai-craftsman/src/utils/concurrent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const promiseAllWithConcurrencyLimit = <T>(
}
};

if (tasks.length === 0) return resolve([]);
for (let i = 0; i < Math.min(limit, tasks.length); i++) {
executeTask();
}
Expand Down
101 changes: 64 additions & 37 deletions packages/ai-craftsman/src/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,41 @@ const getOctokit = () => {

export const eventPath = process.env["GITHUB_EVENT_PATH"] ?? "";
export const repository = github.context.payload?.repository;
export const commentId = github.context?.payload?.comment?.["id"] ?? undefined;
export const comment = github.context?.payload?.comment?.["body"] || undefined;

const getOwnerAndRepo = () => {
const { owner, name } = repository ?? {};
return { owner: owner?.login ?? "", repo: name ?? "" };
};

const getPullNumberAndCommitId = async () => {
const githubEvent = JSON.parse(await fs.promises.readFile(eventPath, "utf8"));
const pullNumber = github.context.payload.pull_request?.number ?? 0;
const commitId = githubEvent.pull_request.head.sha ?? "";
return { pullNumber, commitId };
const getPullNumber = () => {
let number = github.context.payload.pull_request?.number;
if (number) return number;
number = github.context.issue?.number;
if (number) return number;
throw new Error("Cannot get pull request number.");
};

export const getCommitId = async (): Promise<string> => {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { data } = await octokit.rest.pulls.get({
owner,
repo,
pull_number: getPullNumber(),
});
return data.head.sha;
};

export const isPrDraft = async (): Promise<boolean> => {
try {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { pullNumber } = await getPullNumberAndCommitId();
const { data } = await octokit.rest.pulls.get({
owner,
repo,
pull_number: pullNumber,
pull_number: getPullNumber(),
});
return data.draft === true || data.title.startsWith("[WIP]");
} catch (error) {
Expand All @@ -46,16 +58,15 @@ export const getCommentsOrderByCreatedAtDesc = async () => {
try {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { pullNumber } = await getPullNumberAndCommitId();
const { data: reviews } = await octokit.rest.pulls.listReviewComments({
owner,
repo,
pull_number: pullNumber,
pull_number: getPullNumber(),
});
const { data: comments } = await octokit.rest.issues.listComments({
owner,
repo,
issue_number: pullNumber,
issue_number: getPullNumber(),
});

return [...reviews, ...comments].sort((a, b) => {
Expand All @@ -81,19 +92,46 @@ const appendCommitId = (body: string, commitId: string) => {
export const getLatestCommitIdByTheApp = async (): Promise<string> => {
const comments = await getCommentsOrderByCreatedAtDesc();
const comment = comments.find((c) => c.body?.includes(`<!-- COMMIT_ID: `));
return comment?.body?.match(/<!-- COMMIT_ID:\s*(.+)\s*-->/)?.[1] ?? "";
return comment?.body?.match(/<!-- COMMIT_ID:\s*(.+?)\s*-->/)?.[1] ?? "";
};

export const reactToComment = async (
commentId: number,
content:
| "+1"
| "-1"
| "laugh"
| "confused"
| "heart"
| "hooray"
| "rocket"
| "eyes"
) => {
try {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { data } = await octokit.rest.reactions.createForIssueComment({
owner,
repo,
comment_id: commentId,
content: content,
});
return data;
} catch (error) {
console.error(error);
return undefined;
}
};

export const postComment = async (body: string) => {
try {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { pullNumber, commitId } = await getPullNumberAndCommitId();
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: pullNumber,
body: appendCommitId(body, commitId),
issue_number: getPullNumber(),
body: appendCommitId(body, await getCommitId()),
});
} catch (error) {
console.error(error);
Expand All @@ -109,11 +147,11 @@ export const postReviewComment = async (
try {
const octokit = getOctokit();
const { owner, repo } = getOwnerAndRepo();
const { pullNumber, commitId } = await getPullNumberAndCommitId();
const commitId = await getCommitId();
await octokit.rest.pulls.createReviewComment({
owner,
repo,
pull_number: pullNumber,
pull_number: getPullNumber(),
commit_id: commitId,
path,
start_line: startLine,
Expand All @@ -126,39 +164,28 @@ export const postReviewComment = async (
}
};

export const getBaseRef = async () => {
const ref = github.context.payload.pull_request?.["base"]?.ref;
if (ref) return ref;
export const getRef = async () => {
const base = github.context.payload.pull_request?.["base"]?.sha;
const head = github.context.payload.pull_request?.["head"]?.sha;
if (base && head) return { base, head };
const { owner, repo } = getOwnerAndRepo();
const pullNumber = github.context.payload.issue?.["pull_request"]?.number;
const octokit = getOctokit();
const { data: pullRequest } = await octokit.pulls.get({
owner,
repo,
pull_number: pullNumber,
pull_number: getPullNumber(),
});

return pullRequest.base.ref;
return { base: pullRequest.base.sha, head: pullRequest.head.sha };
};

export interface Diff {
path: string;
diff: string;
}

export const getDiff = (targetBranch: string): Diff[] => {
const currentBranch = execSync("git rev-parse --abbrev-ref HEAD")
.toString()
.trim();

const branch =
currentBranch === targetBranch
? `HEAD~1..HEAD`
: `origin/${targetBranch}..${currentBranch}`;

const filePaths = execSync(
`git --no-pager diff --minimal --name-only ${branch}`
)
export const getDiff = (base: string, head: string): Diff[] => {
const command = `git --no-pager diff --minimal --name-only ${base}...${head}`;
const filePaths = execSync(command)
.toString()
.split("\n")
.map((ln) => ln.trim())
Expand All @@ -169,7 +196,7 @@ export const getDiff = (targetBranch: string): Diff[] => {
if (!fs.existsSync(path)) {
continue;
}
const diff = execSync(`git --no-pager diff ${branch} ${path}`)
const diff = execSync(`git --no-pager diff ${base}...${head} ${path}`)
.toString()
.trim();
diffs.push({ path, diff });
Expand Down

0 comments on commit fa4c2fc

Please sign in to comment.