mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-21 16:01:04 +00:00
ci: trigger ai reviews and add maintainer
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
# GitHub usernames with Herdr maintainer authority, one per line.
|
||||
# Maintainers must also use the canonical repository and have write access.
|
||||
ogulcancelik
|
||||
Pimpmuckl
|
||||
kangal-bot
|
||||
|
||||
@@ -2,7 +2,7 @@ name: PR Gate
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, closed, reopened]
|
||||
types: [opened, closed, reopened, ready_for_review]
|
||||
|
||||
concurrency:
|
||||
group: pr-gate-${{ github.event.pull_request.number }}
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
49699333, // dependabot[bot]
|
||||
41898282, // github-actions[bot]
|
||||
]);
|
||||
const REVIEW_LABEL = 'ai-review';
|
||||
const REVIEW_TRIGGER_MARKER = '<!-- herdr:ai-review-trigger -->';
|
||||
const COMMENT_MARKER = '<!-- herdr:pr-gate -->';
|
||||
|
||||
const pullNumber = context.payload.pull_request.number;
|
||||
@@ -85,16 +85,6 @@ jobs:
|
||||
return ['admin', 'maintain', 'write'].includes(await getPermission(username));
|
||||
}
|
||||
|
||||
async function currentLabels() {
|
||||
const labels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
return new Set(labels.map(label => label.name));
|
||||
}
|
||||
|
||||
async function hasVerifiedRecovery() {
|
||||
const events = await github.paginate(github.rest.issues.listEventsForTimeline, {
|
||||
owner: context.repo.owner,
|
||||
@@ -108,28 +98,31 @@ jobs:
|
||||
await isVerifiedMaintainer(latestStateEvent.actor?.login);
|
||||
}
|
||||
|
||||
async function addReviewLabel() {
|
||||
if ((await currentLabels()).has(REVIEW_LABEL)) return;
|
||||
await github.rest.issues.addLabels({
|
||||
async function requestAiReviews() {
|
||||
if (pr.draft) {
|
||||
core.info(`PR #${pullNumber} is a draft; deferring AI reviews until ready`);
|
||||
return;
|
||||
}
|
||||
|
||||
const marker = REVIEW_TRIGGER_MARKER;
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullNumber,
|
||||
labels: [REVIEW_LABEL],
|
||||
per_page: 100,
|
||||
});
|
||||
}
|
||||
|
||||
async function removeReviewLabel() {
|
||||
if (!(await currentLabels()).has(REVIEW_LABEL)) return;
|
||||
try {
|
||||
await github.request('DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}', {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullNumber,
|
||||
name: REVIEW_LABEL,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.status !== 404) throw error;
|
||||
if (comments.some(comment =>
|
||||
comment.user?.id === KANGAL_USER_ID && comment.body?.includes(marker))) {
|
||||
core.info(`AI reviews already requested for PR #${pullNumber}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullNumber,
|
||||
body: [marker, '@coderabbitai review', '@greptileai'].join('\n'),
|
||||
});
|
||||
}
|
||||
|
||||
async function upsertGateComment(message) {
|
||||
@@ -163,10 +156,9 @@ jobs:
|
||||
async function closePullRequest(reason) {
|
||||
if (await hasVerifiedRecovery()) {
|
||||
core.info(`PR #${pullNumber} was recovered by a verified maintainer; leaving it open`);
|
||||
await addReviewLabel();
|
||||
await requestAiReviews();
|
||||
return;
|
||||
}
|
||||
await removeReviewLabel();
|
||||
const message = [
|
||||
`Hi @${prAuthor}, thanks for your interest in contributing.`,
|
||||
'',
|
||||
@@ -185,7 +177,7 @@ jobs:
|
||||
await upsertGateComment(message);
|
||||
if (await hasVerifiedRecovery()) {
|
||||
core.info(`PR #${pullNumber} was recovered while the gate was running; leaving it open`);
|
||||
await addReviewLabel();
|
||||
await requestAiReviews();
|
||||
return;
|
||||
}
|
||||
await github.rest.pulls.update({
|
||||
@@ -196,26 +188,22 @@ jobs:
|
||||
});
|
||||
}
|
||||
|
||||
if (pr.state === 'closed') {
|
||||
await removeReviewLabel();
|
||||
return;
|
||||
}
|
||||
if (pr.state === 'closed') return;
|
||||
|
||||
if (CI_ONLY_PR_AUTHOR_IDS.has(pr.user.id)) {
|
||||
core.info(`Leaving CI-only bot PR open without automated AI review: ${prAuthor}`);
|
||||
await removeReviewLabel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (await isVerifiedMaintainer(prAuthor)) {
|
||||
core.info(`${prAuthor} is a verified maintainer`);
|
||||
await addReviewLabel();
|
||||
await requestAiReviews();
|
||||
return;
|
||||
}
|
||||
|
||||
if (approvedContributors.has(prAuthor.toLowerCase())) {
|
||||
core.info(`${prAuthor} is in the approved contributors list`);
|
||||
await addReviewLabel();
|
||||
await requestAiReviews();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user