Skip to content

feat: add --add-labels and --remove-labels flags#44

Open
michael-ford wants to merge 1 commit intojoa23:mainfrom
michael-ford:feature/add-remove-labels
Open

feat: add --add-labels and --remove-labels flags#44
michael-ford wants to merge 1 commit intojoa23:mainfrom
michael-ford:feature/add-remove-labels

Conversation

@michael-ford
Copy link
Copy Markdown

Summary

The existing --labels flag on issues update uses replace semantics -- it sends a full labelIds array to the Linear API, wiping any existing labels on the issue. This makes it difficult to incrementally manage labels without knowing and re-specifying all current labels.

This PR adds two new flags:

  • --add-labels -- adds the specified labels without removing existing ones
  • --remove-labels -- removes the specified labels without affecting others

Both flags can be used together in a single command. They are mutually exclusive with --labels (which remains as the replace-all mode).

How it works

Since the Linear API's labelIds field is always a full replacement, the implementation:

  1. Fetches the issue's current labels via the existing GetIssue query (which already returns labels { nodes { id name } })
  2. Resolves the user-provided label names to UUIDs using the existing ResolveLabelIdentifier method
  3. Merges (for --add-labels) or subtracts (for --remove-labels) using a set
  4. Sends the combined label ID set via labelIds in the update mutation

No new GraphQL queries or API calls are needed beyond what already exists.

Usage examples

# Add labels without removing existing ones
linear issues update CEN-123 --add-labels "bug,urgent"

# Remove specific labels
linear issues update CEN-123 --remove-labels "wontfix"

# Add and remove labels in one command
linear issues update CEN-123 --add-labels "in-progress" --remove-labels "backlog"

# Replace all labels (existing behavior, unchanged)
linear issues update CEN-123 --labels "backend,security"

# Error: cannot mix replace with additive/subtractive
linear issues update CEN-123 --labels "foo" --add-labels "bar"
# => --labels cannot be combined with --add-labels or --remove-labels

Files changed

  • internal/cli/issues.go -- new flag definitions, mutual exclusivity validation, updated help text and examples
  • internal/service/issue.go -- AddLabelIDs/RemoveLabelIDs fields on UpdateIssueInput, merge/subtract logic, extractCurrentLabelIDs helper

Test plan

  • Build succeeds: go build -o linear ./cmd/linear/
  • All existing tests pass: go test ./... (396 tests)
  • --add-labels and --remove-labels appear in linear issues update --help
  • --labels with --add-labels returns an error
  • --labels with --remove-labels returns an error
  • --add-labels "newlabel" adds the label without removing existing labels
  • --remove-labels "oldlabel" removes only the specified label
  • --add-labels "a" --remove-labels "b" works together in one command
  • --labels "a,b" still works as replace-all (existing behavior preserved)

The existing --labels flag uses replace semantics, sending a full
labelIds array to the Linear API and wiping any existing labels.
This is problematic for workflows that need to incrementally add
or remove labels without affecting the rest.

New flags:
- --add-labels: adds labels to the issue without removing existing ones
- --remove-labels: removes specific labels without affecting others

Both can be used together in a single command. They are mutually
exclusive with --labels (which remains as the replace-all mode).

Implementation:
- CLI layer: new flags with mutual exclusivity validation
- Service layer: fetch current labels from issue, resolve names to
  IDs, merge/subtract using a set, then send combined labelIds
- No new GraphQL queries needed: GetIssue already returns labels
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant