Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
daa417a
ci: add dedicated evaluation step for missing priority labels
cocosheng-g May 11, 2026
2d09d9d
fix(ci): ensure status/bot-triaged and status/manual-triage are mutua…
cocosheng-g May 11, 2026
de7d4ba
fix(ci): strictly enforce single area label in prompt and script
cocosheng-g May 11, 2026
109ff9f
ci: add cleanup step for multiple area labels
cocosheng-g May 11, 2026
c3c5d14
ci: use ai to resolve multiple area labels intelligently
cocosheng-g May 11, 2026
f28027d
ci: enforce mutually exclusive priority labels and clean up conflicts
cocosheng-g May 11, 2026
004db14
test: temporarily limit triage to 5 issues
cocosheng-g May 11, 2026
94ec321
fix(ci): track new conflict script and remove old multiple area clean…
cocosheng-g May 11, 2026
c664b6e
chore: revert temporary triage limits back to production defaults
cocosheng-g May 11, 2026
a7281e1
test: temporarily limit triage to 2 issues
cocosheng-g May 11, 2026
e0df9f2
chore: revert temporary triage limits back to production defaults again
cocosheng-g May 11, 2026
228fd68
test: temporarily limit triage to 1 issue
cocosheng-g May 11, 2026
42b22dc
refactor(ci): decouple standard and effort triage steps to reduce tok…
cocosheng-g May 11, 2026
154455a
chore: revert temporary triage limits back to production defaults
cocosheng-g May 11, 2026
0839a6d
fix(ci): remove bot-triaged exclusion from effort query to unblock ba…
cocosheng-g May 11, 2026
dec6be3
test: temporarily limit triage to 5 issues
cocosheng-g May 11, 2026
09e33a9
fix(ci): disable telemetry in effort triage step to prevent docker co…
cocosheng-g May 11, 2026
405a0c6
fix(ci): re-enable telemetry for effort triage by manually stopping d…
cocosheng-g May 11, 2026
54ec400
fix(ci): use docker rm -f to forcefully clear container name conflict
cocosheng-g May 11, 2026
ba97409
chore: revert temporary triage limits back to production defaults
cocosheng-g May 11, 2026
0b0bdd4
ci: permanently set standard triage limits to 50 and effort to 5
cocosheng-g May 11, 2026
fc349e8
chore: fix unquoted string in triage workflow
cocosheng-g May 11, 2026
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
45 changes: 41 additions & 4 deletions .github/scripts/apply-issue-labels.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,51 @@ module.exports = async ({ github, context, core }) => {
continue;
}

const labelsToAdd = entry.labels_to_add || [];
labelsToAdd.push('status/bot-triaged');

let labelsToAdd = entry.labels_to_add || [];
let labelsToRemove = entry.labels_to_remove || [];

labelsToRemove.push('status/need-triage');
// Deduplicate array

if (labelsToAdd.includes('status/manual-triage')) {
// If the AI flagged it for manual triage, remove bot-triaged if it exists
labelsToRemove.push('status/bot-triaged');
// Ensure we don't accidentally try to add bot-triaged if the AI returned it
labelsToAdd = labelsToAdd.filter((l) => l !== 'status/bot-triaged');
} else {
// Standard successful bot triage
labelsToAdd.push('status/bot-triaged');
}

// Deduplicate arrays
labelsToAdd = [...new Set(labelsToAdd)];
labelsToRemove = [...new Set(labelsToRemove)];

// Enforce mutually exclusive area labels
const areaLabelsToAdd = labelsToAdd.filter((l) => l.startsWith('area/'));
if (areaLabelsToAdd.length > 1) {
core.warning(
`Issue #${issueNumber} has multiple area labels to add: ${areaLabelsToAdd.join(', ')}. Keeping only the first one.`,
);
const firstArea = areaLabelsToAdd[0];
labelsToAdd = labelsToAdd.filter(
(l) => !l.startsWith('area/') || l === firstArea,
);
}

// Enforce mutually exclusive priority labels
const priorityLabelsToAdd = labelsToAdd.filter((l) =>
l.startsWith('priority/'),
);
if (priorityLabelsToAdd.length > 1) {
core.warning(
`Issue #${issueNumber} has multiple priority labels to add: ${priorityLabelsToAdd.join(', ')}. Keeping only the first one.`,
);
const firstPriority = priorityLabelsToAdd[0];
labelsToAdd = labelsToAdd.filter(
(l) => !l.startsWith('priority/') || l === firstPriority,
);
}

if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
Expand Down
60 changes: 60 additions & 0 deletions .github/scripts/find-conflicting-labels.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

const fs = require('node:fs');

module.exports = async ({ github, context, core }) => {
core.info('Fetching open issues to check for conflicting labels...');

const issues = await github.paginate(github.rest.issues.listForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
});

const conflictingLabelIssues = [];

for (const issue of issues) {
if (issue.pull_request) continue;

const areaLabels = issue.labels
.filter((l) => l.name && l.name.startsWith('area/'))
.map((l) => l.name);

const priorityLabels = issue.labels
.filter((l) => l.name && l.name.startsWith('priority/'))
.map((l) => l.name);

if (areaLabels.length > 1 || priorityLabels.length > 1) {
let message = `Issue #${issue.number} has conflicting labels:`;
if (areaLabels.length > 1)
message += ` multiple areas (${areaLabels.join(', ')}).`;
if (priorityLabels.length > 1)
message += ` multiple priorities (${priorityLabels.join(', ')}).`;

core.info(message);

conflictingLabelIssues.push({
number: issue.number,
title: issue.title,
body: issue.body || '',
});
}
}

// Limit to 50 to avoid overwhelming the AI in a single run
const issuesToProcess = conflictingLabelIssues.slice(0, 50);

fs.writeFileSync(
'conflicting_labels_issues.json',
JSON.stringify(issuesToProcess, null, 2),
);

core.info(
`Found ${conflictingLabelIssues.length} issues with conflicting labels. Wrote ${issuesToProcess.length} to conflicting_labels_issues.json`,
);
};
Loading
Loading