ci(labeler): compact noisy module labels for tool/provider/channel
This commit is contained in:
parent
389496823d
commit
004fc4590f
3 changed files with 53 additions and 4 deletions
55
.github/workflows/labeler.yml
vendored
55
.github/workflows/labeler.yml
vendored
|
|
@ -418,6 +418,48 @@ jobs:
|
||||||
return refined;
|
return refined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compactNoisyModuleLabels(labels) {
|
||||||
|
const noisyPrefixes = new Set(["tool", "provider", "channel"]);
|
||||||
|
const groupedSegments = new Map();
|
||||||
|
const compacted = new Set();
|
||||||
|
const forcePathPrefixes = new Set();
|
||||||
|
|
||||||
|
for (const label of labels) {
|
||||||
|
const parsed = parseModuleLabel(label);
|
||||||
|
if (!parsed) continue;
|
||||||
|
if (!groupedSegments.has(parsed.prefix)) {
|
||||||
|
groupedSegments.set(parsed.prefix, new Set());
|
||||||
|
}
|
||||||
|
groupedSegments.get(parsed.prefix).add(parsed.segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const label of labels) {
|
||||||
|
const parsed = parseModuleLabel(label);
|
||||||
|
if (!parsed) continue;
|
||||||
|
if (!noisyPrefixes.has(parsed.prefix)) {
|
||||||
|
compacted.add(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [prefix, segments] of groupedSegments) {
|
||||||
|
if (!noisyPrefixes.has(prefix)) continue;
|
||||||
|
|
||||||
|
const specificSegments = [...segments].filter((segment) => segment !== "core");
|
||||||
|
const uniqueSpecificSegments = [...new Set(specificSegments)];
|
||||||
|
|
||||||
|
if (uniqueSpecificSegments.length === 1) {
|
||||||
|
compacted.add(`${prefix}:${uniqueSpecificSegments[0]}`);
|
||||||
|
} else {
|
||||||
|
forcePathPrefixes.add(prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleLabels: compacted,
|
||||||
|
forcePathPrefixes,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function colorForLabel(label) {
|
function colorForLabel(label) {
|
||||||
if (staticLabelColors[label]) return staticLabelColors[label];
|
if (staticLabelColors[label]) return staticLabelColors[label];
|
||||||
const matchedPrefix = Object.keys(modulePrefixColors).find((prefix) => label.startsWith(prefix));
|
const matchedPrefix = Object.keys(modulePrefixColors).find((prefix) => label.startsWith(prefix));
|
||||||
|
|
@ -558,8 +600,11 @@ jobs:
|
||||||
}
|
}
|
||||||
|
|
||||||
const refinedModuleLabels = refineModuleLabels(detectedModuleLabels);
|
const refinedModuleLabels = refineModuleLabels(detectedModuleLabels);
|
||||||
|
const compactedModuleState = compactNoisyModuleLabels(refinedModuleLabels);
|
||||||
|
const selectedModuleLabels = compactedModuleState.moduleLabels;
|
||||||
|
const forcePathPrefixes = compactedModuleState.forcePathPrefixes;
|
||||||
const modulePrefixesWithLabels = new Set(
|
const modulePrefixesWithLabels = new Set(
|
||||||
[...refinedModuleLabels]
|
[...selectedModuleLabels]
|
||||||
.map((label) => parseModuleLabel(label)?.prefix)
|
.map((label) => parseModuleLabel(label)?.prefix)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
);
|
);
|
||||||
|
|
@ -571,9 +616,11 @@ jobs:
|
||||||
});
|
});
|
||||||
const currentLabelNames = currentLabels.map((label) => label.name);
|
const currentLabelNames = currentLabels.map((label) => label.name);
|
||||||
const currentPathLabels = currentLabelNames.filter((label) => managedPathLabelSet.has(label));
|
const currentPathLabels = currentLabelNames.filter((label) => managedPathLabelSet.has(label));
|
||||||
|
const candidatePathLabels = new Set([...currentPathLabels, ...forcePathPrefixes]);
|
||||||
|
|
||||||
const dedupedPathLabels = currentPathLabels.filter((label) => {
|
const dedupedPathLabels = [...candidatePathLabels].filter((label) => {
|
||||||
if (label === "core") return true;
|
if (label === "core") return true;
|
||||||
|
if (forcePathPrefixes.has(label)) return true;
|
||||||
return !modulePrefixesWithLabels.has(label);
|
return !modulePrefixesWithLabels.has(label);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -627,7 +674,7 @@ jobs:
|
||||||
manualRiskOverrideLabel,
|
manualRiskOverrideLabel,
|
||||||
...managedPathLabels,
|
...managedPathLabels,
|
||||||
...contributorTierLabels,
|
...contributorTierLabels,
|
||||||
...refinedModuleLabels,
|
...selectedModuleLabels,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (const label of labelsToEnsure) {
|
for (const label of labelsToEnsure) {
|
||||||
|
|
@ -663,7 +710,7 @@ jobs:
|
||||||
const manualRiskSelection =
|
const manualRiskSelection =
|
||||||
currentLabelNames.find((label) => computedRiskLabels.includes(label)) || riskLabel;
|
currentLabelNames.find((label) => computedRiskLabels.includes(label)) || riskLabel;
|
||||||
|
|
||||||
const moduleLabelList = sortModuleLabels([...refinedModuleLabels]);
|
const moduleLabelList = sortModuleLabels([...selectedModuleLabels]);
|
||||||
const contributorLabelList = contributorTierLabel ? [contributorTierLabel] : [];
|
const contributorLabelList = contributorTierLabel ? [contributorTierLabel] : [];
|
||||||
const selectedRiskLabels = hasManualRiskOverride
|
const selectedRiskLabels = hasManualRiskOverride
|
||||||
? sortByPriority([manualRiskSelection, manualRiskOverrideLabel], riskPriorityIndex)
|
? sortByPriority([manualRiskSelection, manualRiskOverrideLabel], riskPriorityIndex)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
|
||||||
- Additional behavior: label descriptions are auto-managed as hover tooltips to explain each auto-judgment rule
|
- Additional behavior: label descriptions are auto-managed as hover tooltips to explain each auto-judgment rule
|
||||||
- Additional behavior: provider-related keywords in provider/config/onboard/integration changes are promoted to `provider:*` labels (for example `provider:kimi`, `provider:deepseek`)
|
- Additional behavior: provider-related keywords in provider/config/onboard/integration changes are promoted to `provider:*` labels (for example `provider:kimi`, `provider:deepseek`)
|
||||||
- Additional behavior: hierarchical de-duplication keeps only the most specific scope labels (for example `tool:composio` suppresses `tool:core` and `tool`)
|
- Additional behavior: hierarchical de-duplication keeps only the most specific scope labels (for example `tool:composio` suppresses `tool:core` and `tool`)
|
||||||
|
- Additional behavior: noisy namespaces (`tool`, `provider`, `channel`) are compacted — one specific module keeps `prefix:component`; multiple specifics collapse to just `prefix`
|
||||||
- Additional behavior: applies contributor tiers on PRs by merged PR count (`experienced` >=10, `principal` >=20, `distinguished` >=50)
|
- Additional behavior: applies contributor tiers on PRs by merged PR count (`experienced` >=10, `principal` >=20, `distinguished` >=50)
|
||||||
- Additional behavior: final label set is priority-sorted (`risk:*` first, then `size:*`, then contributor tier, then module/path labels)
|
- Additional behavior: final label set is priority-sorted (`risk:*` first, then `size:*`, then contributor tier, then module/path labels)
|
||||||
- Additional behavior: risk + size labels are auto-corrected on manual PR label edits (`labeled`/`unlabeled` events); apply `risk: manual` when maintainers intentionally override automated risk selection
|
- Additional behavior: risk + size labels are auto-corrected on manual PR label edits (`labeled`/`unlabeled` events); apply `risk: manual` when maintainers intentionally override automated risk selection
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ Maintain these branch protection rules on `main`:
|
||||||
|
|
||||||
- Contributor opens PR with full `.github/pull_request_template.md`.
|
- Contributor opens PR with full `.github/pull_request_template.md`.
|
||||||
- `PR Labeler` applies scope/path labels + size labels + risk labels + module labels (for example `channel:telegram`, `provider:kimi`, `tool:shell`) and contributor tiers by merged PR count (`experienced` >=10, `principal` >=20, `distinguished` >=50), while de-duplicating less-specific scope labels when a more specific module label is present.
|
- `PR Labeler` applies scope/path labels + size labels + risk labels + module labels (for example `channel:telegram`, `provider:kimi`, `tool:shell`) and contributor tiers by merged PR count (`experienced` >=10, `principal` >=20, `distinguished` >=50), while de-duplicating less-specific scope labels when a more specific module label is present.
|
||||||
|
- For `tool` / `provider` / `channel`, module labels are compacted to reduce noise: one specific module keeps `prefix:component`, but multiple specifics collapse to the base scope label.
|
||||||
- Label ordering is priority-first: `risk:*` -> `size:*` -> contributor tier -> module/path labels.
|
- Label ordering is priority-first: `risk:*` -> `size:*` -> contributor tier -> module/path labels.
|
||||||
- Hovering a label in GitHub shows its auto-managed description (rule/threshold summary).
|
- Hovering a label in GitHub shows its auto-managed description (rule/threshold summary).
|
||||||
- `Auto Response` posts first-time guidance and handles label-driven routing for low-signal items.
|
- `Auto Response` posts first-time guidance and handles label-driven routing for low-signal items.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue