fix: ensure clean label transitions by removing all state labels

Problem:
GitHub was showing confusing label transitions like:
- 'added To Do Doing and removed To Do'
- 'added To Test Testing Done and removed Doing To Test Testing'

This occurred when issues had multiple state labels simultaneously
(due to bugs, manual edits, or failed transitions).

Root Cause:
The old transitionLabel() only removed the 'from' label and added
the 'to' label. If other state labels existed on the issue, they
would remain, causing messy multi-label states.

Solution:
1. Fetch the current issue to inspect all labels
2. Find ALL state labels on the issue (not just 'from')
3. Remove ALL state labels in a single operation
4. Add only the new 'to' label

This ensures atomic, clean transitions that display on GitHub as
a single 'removed X, added Y' operation, even if the issue
previously had multiple state labels.

Changes:
- GitHubProvider.transitionLabel(): Remove all state labels before adding new one
- GitLabProvider.transitionLabel(): Same fix for GitLab consistency

Addresses issue #97
This commit is contained in:
Lauren ten Hoor
2026-02-10 17:59:57 +08:00
parent 6c20a2c38c
commit c973c04635
2 changed files with 62 additions and 8 deletions

View File

@@ -151,11 +151,38 @@ export class GitHubProvider implements TaskManager {
from: StateLabel,
to: StateLabel,
): Promise<void> {
await this.gh([
// Fetch current issue to get all labels
const issue = await this.getIssue(issueId);
// Find all state labels currently on the issue
const currentStateLabels = issue.labels.filter((label) =>
STATE_LABELS.includes(label as StateLabel),
);
// If no state labels to remove, just add the new one
if (currentStateLabels.length === 0) {
await this.gh([
"issue", "edit", String(issueId),
"--add-label", to,
]);
return;
}
// Remove all state labels and add the new one in a single operation
// This ensures clean transitions: "removed X, added Y" instead of messy multi-label operations
const args = [
"issue", "edit", String(issueId),
"--remove-label", from,
"--add-label", to,
]);
];
// Add all current state labels to remove
for (const label of currentStateLabels) {
args.push("--remove-label", label);
}
// Add the new state label
args.push("--add-label", to);
await this.gh(args);
}
async closeIssue(issueId: number): Promise<void> {