mirror of
https://github.com/github/awesome-copilot.git
synced 2026-10-14 07:44:43 +00:00
feat(external-plugins): fast-track first-party reviews and note org ownership
Auto-accept first-party cards on the review board with /approve suggested, skipping AI review unless the maintainer opts the card back into Unreviewed. Show ownership and fast-track pills on cards. Add a "Repository owner" reviewer-signal row to intake comments for organization-owned repositories; user-owned repositories get no row. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 821f4796-505e-4fb8-96cf-0b5bbf80a636
This commit is contained in:
co-authored by
Copilot App
parent
36667634be
commit
b653c23244
@@ -18,6 +18,11 @@ Open it by asking Copilot to "open the plugin review board" (canvas id `external
|
||||
back and it's recorded on the card along with your guidance.
|
||||
- **Refresh** fetches open `external-plugin` + `ready-for-review` issues, adds new ones, and removes any
|
||||
that are closed or no longer ready for review.
|
||||
- **First-party fast-track**: cards labelled `first party` (repository owned by a Microsoft/GitHub
|
||||
organization) skip AI review and go straight to *Accept* with a suggested `/approve`. Only submissions
|
||||
that passed automated intake reach the board, so hard validation failures are still held back by intake.
|
||||
Fast-track never overrides an existing review or a bucket you chose; drag a card to *Unreviewed* to opt it
|
||||
out and have it reviewed normally. Cards show *First party* / *Third party* pills from the intake labels.
|
||||
- **Details panel** shows the AI review, the rendered issue body, and all comments.
|
||||
- **Quick actions** post `/approve` (with an optional note) or `/reject <reason>` straight to the issue
|
||||
after a confirm click. The reject reason is prefilled from the AI's suggested comment.
|
||||
|
||||
@@ -15,6 +15,33 @@ export const COLUMNS = [
|
||||
];
|
||||
|
||||
const HISTORY_LIMIT = 200;
|
||||
export const FIRST_PARTY_LABEL = "first party";
|
||||
|
||||
// Submissions from first-party organizations skip AI triage and land in Accept. Only cards without
|
||||
// an AI review, queued review, or manual bucket are fast-tracked so maintainer choices are kept;
|
||||
// dragging a card back to Unreviewed opts it out so it gets a normal AI review.
|
||||
function applyFirstPartyFastTrack(item) {
|
||||
if (
|
||||
!item.labels?.includes(FIRST_PARTY_LABEL) ||
|
||||
item.fastTrackDismissed ||
|
||||
item.decision ||
|
||||
item.review ||
|
||||
item.manualColumn ||
|
||||
item.reviewStatus === "queued"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
item.review = {
|
||||
recommendation: "accept",
|
||||
fastTracked: true,
|
||||
rationale:
|
||||
"First-party submission (repository owned by a Microsoft/GitHub organization) that passed automated intake validation; fast-tracked to approval.",
|
||||
suggestedComment: "/approve",
|
||||
reviewedAt: new Date().toISOString(),
|
||||
};
|
||||
item.reviewStatus = "reviewed";
|
||||
return true;
|
||||
}
|
||||
|
||||
function newQueueId() {
|
||||
return randomBytes(6).toString("base64url");
|
||||
@@ -101,6 +128,7 @@ export class BoardStore {
|
||||
const incoming = new Map(issues.map((issue) => [String(issue.number), issue]));
|
||||
const added = [];
|
||||
const removed = [];
|
||||
const fastTracked = [];
|
||||
for (const [key, issue] of incoming) {
|
||||
const existing = this.state.items[key];
|
||||
if (existing) {
|
||||
@@ -123,6 +151,7 @@ export class BoardStore {
|
||||
};
|
||||
added.push(issue.number);
|
||||
}
|
||||
if (applyFirstPartyFastTrack(this.state.items[key])) fastTracked.push(issue.number);
|
||||
}
|
||||
for (const key of Object.keys(this.state.items)) {
|
||||
if (!incoming.has(key)) {
|
||||
@@ -132,7 +161,7 @@ export class BoardStore {
|
||||
}
|
||||
this.state.lastRefreshedAt = new Date().toISOString();
|
||||
await this.commit();
|
||||
return { added, removed, total: incoming.size };
|
||||
return { added, removed, fastTracked, total: incoming.size };
|
||||
}
|
||||
|
||||
pendingReview(numbers) {
|
||||
@@ -218,6 +247,7 @@ export class BoardStore {
|
||||
const item = this.getItem(number);
|
||||
if (item.decision) throw new Error(`#${number} has already been actioned.`);
|
||||
if (column === "unreviewed") {
|
||||
if (item.review?.fastTracked || item.labels?.includes(FIRST_PARTY_LABEL)) item.fastTrackDismissed = true;
|
||||
item.review = null;
|
||||
item.reviewStatus = "unreviewed";
|
||||
item.manualColumn = null;
|
||||
|
||||
@@ -115,8 +115,15 @@ function signalPills(item) {
|
||||
pills.push(h("span", { class: `pill pill-${level.toLowerCase()}`, title: "AGT contributor risk" }, `AGT ${level}`));
|
||||
} else if (label === "external-plugin-canvas") {
|
||||
pills.push(h("span", { class: "pill" }, "canvas"));
|
||||
} else if (label === "first party") {
|
||||
pills.push(h("span", { class: "pill pill-first-party", title: "Repository owned by a Microsoft/GitHub organization" }, "First party"));
|
||||
} else if (label === "third party") {
|
||||
pills.push(h("span", { class: "pill pill-third-party", title: "Repository owned by a third-party organization" }, "Third party"));
|
||||
}
|
||||
}
|
||||
if (item.review?.fastTracked && !item.decision) {
|
||||
pills.push(h("span", { class: "pill pill-approve", title: "First-party submission fast-tracked to approval" }, "Fast-tracked"));
|
||||
}
|
||||
if (item.decision) {
|
||||
pills.push(h("span", { class: `pill pill-${item.decision.kind}` }, item.decision.kind === "approve" ? "Approved" : "Rejected"));
|
||||
} else if (item.pendingDecision) {
|
||||
@@ -391,7 +398,7 @@ function renderReview(item) {
|
||||
return wrapper;
|
||||
}
|
||||
const rows = [
|
||||
["Recommendation", RECOMMENDATION_LABELS[review.recommendation] + (item.manualColumn ? ` (you moved it to ${RECOMMENDATION_LABELS[item.manualColumn]})` : "")],
|
||||
["Recommendation", RECOMMENDATION_LABELS[review.recommendation] + (review.fastTracked ? " (first-party fast-track, no AI review)" : "") + (item.manualColumn ? ` (you moved it to ${RECOMMENDATION_LABELS[item.manualColumn]})` : "")],
|
||||
["Plugin", review.pluginName],
|
||||
["Repository", review.repository ? h("a", { href: `https://github.com/${review.repository}`, target: "_blank", rel: "noopener noreferrer" }, review.repository) : null],
|
||||
["Repo facts", review.repoFacts],
|
||||
@@ -546,6 +553,7 @@ ui.refresh.addEventListener("click", () =>
|
||||
const parts = [`${result.total} open`];
|
||||
if (result.added.length) parts.push(`${result.added.length} new`);
|
||||
if (result.removed.length) parts.push(`${result.removed.length} removed`);
|
||||
if (result.fastTracked?.length) parts.push(`${result.fastTracked.length} first-party fast-tracked`);
|
||||
toast(`Refreshed: ${parts.join(", ")}`);
|
||||
if (selected != null && activeTab !== "review") loadDetail(selected, { force: true });
|
||||
} catch (error) {
|
||||
|
||||
@@ -376,6 +376,16 @@ h2 {
|
||||
background: var(--red-muted);
|
||||
color: var(--red);
|
||||
}
|
||||
.pill-first-party {
|
||||
border-color: transparent;
|
||||
background: var(--green-muted);
|
||||
color: var(--green);
|
||||
}
|
||||
.pill-third-party {
|
||||
border-color: transparent;
|
||||
background: var(--purple-muted);
|
||||
color: var(--purple);
|
||||
}
|
||||
.pill-queued {
|
||||
border-color: transparent;
|
||||
background: var(--purple-muted);
|
||||
|
||||
@@ -69,3 +69,14 @@ and read the `/approve` / `/reject` comments on the most recent ones.
|
||||
- `probably-reject` — likely reject, but something specific deserves a quick maintainer look.
|
||||
- `needs-review` — genuine judgement call.
|
||||
- `accept` — fits the approval pattern.
|
||||
|
||||
## Ownership labels
|
||||
|
||||
Intake labels submissions by who owns the plugin repository:
|
||||
|
||||
- `first party` — owned by a Microsoft/GitHub organization (Microsoft, GitHub, Azure, dotnet, MicrosoftDocs,
|
||||
microsoftgraph). The board fast-tracks these straight to `accept` without an AI review. If one is sent for
|
||||
review anyway, recommend `accept` unless there is a hard failure (broken/missing plugin contents,
|
||||
security concern, or something that would have failed intake validation).
|
||||
- `third party` — owned by another organization. This is a signal only; apply the normal decision pattern.
|
||||
- No ownership label — owned by a user account (or ownership couldn't be determined).
|
||||
|
||||
Reference in New Issue
Block a user