Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give the CSSWG a custom triage heuristic. #27

Merged
merged 1 commit into from Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions scanner/github.ts
Expand Up @@ -329,6 +329,7 @@ export async function fetchAllComments(needAllComments: IssueOrPr[], needEarlyCo
}

const Repository = z.object({
nameWithOwner: z.string(),
labels: z.object({
totalCount: z.number(),
nodes: z.array(z.object({
Expand All @@ -346,6 +347,7 @@ export async function getRepo(org, repo): Promise<Repository> {
const result = RepositoryQueryResult.parse(await octokit.graphql(
gql(`query ($owner: String!, $repoName: String!) {
repository(owner: $owner, name: $repoName) {
nameWithOwner
labels(first: 100, query: "Priority") {
totalCount
nodes {
Expand Down
2 changes: 1 addition & 1 deletion scanner/main.ts
Expand Up @@ -59,7 +59,7 @@ async function analyzeRepo(org: string, repoName: string, globalStats: GlobalSta
author: issue.author?.login,
createdAt: issue.createdAt,
sloTimeUsed: Temporal.Duration.from({ seconds: 0 }),
whichSlo: whichSlo(issue),
whichSlo: whichSlo(repo.nameWithOwner, issue),
onAgendaFor: countAgendaTime(issue, now),
labels: issue.labels.nodes.map(label => label.name),
stats: {
Expand Down
18 changes: 18 additions & 0 deletions scanner/per-repo.ts
@@ -0,0 +1,18 @@
import { IssueOrPr } from "./github.js";

const triagePredicates: Record<`${string}/${string}`, (issue: Pick<IssueOrPr, 'labels'>) => boolean> = {
'w3c/csswg-drafts': function (issue: Pick<IssueOrPr, 'labels'>) {
return issue.labels.nodes.length > 0;
},
};

// True if this repository has configured a custom function to say whether an issue is triaged
// without an SLO, instead of the common `Priority: Eventually` label.
export function hasTriagePredicate(repoNameWithOwner: string) {
return repoNameWithOwner in triagePredicates;
}

// True if this issue should be considered triaged without an SLO.
export function isTriaged(repoNameWithOwner: string, issue: Pick<IssueOrPr, 'labels'>): boolean {
return triagePredicates[repoNameWithOwner]?.(issue);
}
16 changes: 11 additions & 5 deletions scanner/slo.ts
Expand Up @@ -2,6 +2,7 @@ import { Temporal } from "@js-temporal/polyfill";
import { SloType } from '@lib/repo-summaries.js';
import assert from "node:assert";
import type { IssueOrPr, Repository } from "./github.js";
import { hasTriagePredicate, isTriaged } from "./per-repo.js";

const PRIORITY_URGENT = "priority: urgent";
const PRIORITY_SOON = "priority: soon";
Expand All @@ -12,19 +13,21 @@ export function NeedsReporterFeedback(label: string) {
return label.toLowerCase() === NEEDS_REPORTER_FEEDBACK;
}

/** Returns whether `repo` has enough labels to mark bugs as triaged.
/** Returns whether `repo` has enough labels or configuration to mark bugs as triaged.
*
* Because different repositories will adopt different subsets of the labels this tool recognizes,
* we should only look for the smallest subset that indicates the repo isn't relying on the triage
* heuristics. For now, that's just the `Priority: Eventually` label.
*
* It's also possible to define a custom isTriaged predicate for each repository.
*/
export function hasLabels(repo: Pick<Repository, 'labels'>): boolean {
return repo.labels.nodes.some(labelNode => labelNode.name === PRIORITY_EVENTUALLY);
export function hasLabels(repo: Pick<Repository, 'nameWithOwner' | 'labels'>): boolean {
return hasTriagePredicate(repo.nameWithOwner) || repo.labels.nodes.some(labelNode => labelNode.name === PRIORITY_EVENTUALLY);
}

export function whichSlo(issue: Pick<IssueOrPr, 'labels' | 'isDraft'>): SloType {
export function whichSlo(repoNameWithOwner: string, issue: Pick<IssueOrPr, 'labels' | 'isDraft'>): SloType {
const labels: string[] = issue.labels.nodes.map(label => label.name.toLowerCase());
if (issue.isDraft || labels.includes(PRIORITY_EVENTUALLY) || labels.includes(NEEDS_REPORTER_FEEDBACK)) {
if (issue.isDraft || labels.includes(NEEDS_REPORTER_FEEDBACK)) {
return "none";
}
if (labels.includes(PRIORITY_URGENT)) {
Expand All @@ -33,6 +36,9 @@ export function whichSlo(issue: Pick<IssueOrPr, 'labels' | 'isDraft'>): SloType
if (labels.includes(PRIORITY_SOON)) {
return "soon";
}
if (labels.includes(PRIORITY_EVENTUALLY) || isTriaged(repoNameWithOwner, issue)) {
return "none";
}
return "triage";
}

Expand Down