Skip to content

feat: add milestones command group and --milestone issue flag - #57

Open
martin-piliar wants to merge 8 commits into
joa23:mainfrom
martin-piliar:feature/milestones-support
Open

feat: add milestones command group and --milestone issue flag#57
martin-piliar wants to merge 8 commits into
joa23:mainfrom
martin-piliar:feature/milestones-support

Conversation

@martin-piliar

Copy link
Copy Markdown

Linear project milestones are fully public in the GraphQL API (projectMilestone* queries and mutations), but this CLI had no support for them at all. This adds:

  • linear milestones list|get|create|update|delete
  • --milestone / -m on issues list|create|update, to filter or assign by milestone
  • Milestone names resolve within a project, the same way project names already resolve within a team
  • issues get now shows the assigned milestone

--project on milestones update only scopes the lookup - it doesn't move the milestone. Point it at a different project and the update just won't find a match there; moving a milestone between projects is a separate Linear mutation (projectMilestoneMove), left out here on purpose.

Usage

linear milestones create "Beta" --project "Q3 Launch" --target-date 2026-08-01
linear milestones update "Beta" --project "Q3 Launch" --name "Private beta"
linear issues create "Ship checkout" --team CEN --project "Q3 Launch" --milestone Beta
linear issues list --team CEN --milestone Beta

Sorry to whoever is going to review this...

Most of it isn't new logic. Adding ProjectMilestone to Issue and a few sibling structs gave them a longer field name, which pushed gofmt to realign every field in those structs - that's whitespace, not code, and it's most of what you'll see in types.go and issues/client.go. The actual new logic is milestones getting the same client → resolver → format → service → CLI treatment every other resource here gets, plus tests.

Test plan

  • go build / vet / test ./... - 17 new test cases
  • gofmt -l clean on everything this PR touches
  • Manual pass against a live workspace: create/rename/delete a milestone, assign an issue with --milestone, reassign one without --project (resolves through the issue's own project), filter issues list --milestone
  • Deleting a milestone with an assigned issue unassigns it instead of erroring, matching Linear own behavior

Adds a Linear API client for project milestones (list/get/create/update/
delete via projectMilestone* GraphQL operations) and links issues to
milestones: Issue.ProjectMilestone, IssueCreateInput/UpdateIssueInput/
IssueFilter gain ProjectMilestoneID, and a ResolveProjectMilestone
resolver (with TTL cache) translates milestone names to UUIDs scoped
to a project.
Adds RenderMilestone/RenderMilestoneList to the Renderer interface and
both implementations (minimal/compact/detailed/full text views, JSON
DTOs), and surfaces the assigned milestone on issue text/JSON output.
New 'linear milestones' command group (list/get/create/update/delete),
plus --milestone on 'issues list/create/update' to filter or assign
issues by project milestone. Milestone names resolve within a project
scope (--project flag or .linear.yaml default).
Adds milestones usage to README, CLAUDE.md, the changelog, and the
embedded /linear skill.
Covers buildCreateInput/buildUpdateInput field presence and the
early-validation error paths on List/Get/Create/Update/Delete.
Covers text (minimal/compact/full) and JSON rendering, including a
regression check for the progress-percentage double-scaling bug.
Covers List/Get/Create/Update/Delete with a mocked
MilestoneClientOperations, including project/milestone identifier
resolution and error propagation. Also asserts --project on update
only scopes the lookup and never moves the milestone between
projects.
CopilotAI review requested due to automatic review settings July 5, 2026 17:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for Linear project milestones across the CLI stack (client/resolver/service/format/commands), including issue filtering/assignment and output rendering.

Changes:

  • Introduces linear milestones list|get|create|update|delete (alias m) with project-scoped name resolution.
  • Adds --milestone/-m to issues list|create|update and includes milestone in issue text/JSON output.
  • Extends core types, client plumbing, formatting/DTOs, and adds milestone-specific tests + docs/changelog updates.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
README.mdDocuments milestone commands and --milestone usage.
pkg/linear/resolver.goAdds project-scoped milestone identifier resolution.
pkg/linear/resolver_cache.goAdds resolver cache for milestone name→ID within a project.
pkg/linear/milestones/client.goNew GraphQL client for project milestone CRUD + list/get.
pkg/linear/milestones/client_test.goUnit tests for milestones client input building + validation.
pkg/linear/issues/client.goAdds projectMilestone fields to issue queries and supports milestone filters/inputs.
pkg/linear/core/types.goAdds ProjectMilestone type and milestone fields on issue-related structs/inputs.
pkg/linear/client.goWires milestones sub-client and exposes milestone operations/resolver passthrough.
internal/skills/linear/SKILL.mdUpdates skill docs/examples to include milestone operations and --milestone.
internal/service/service.goRegisters MilestoneService in service container.
internal/service/search_resolve_test.goUpdates mocks to support milestone resolution.
internal/service/milestone.goNew service layer for milestones + project/milestone resolution logic.
internal/service/milestone_test.goTests milestone service behavior and resolution rules.
internal/service/issue.goAdds milestone filter/assignment resolution in issue service flows.
internal/service/issue_relation_test.goUpdates issue service relation test mocks for milestone resolver method.
internal/service/issue_delegate_test.goUpdates issue delegate test mocks for milestone resolver method.
internal/service/issue_create_test.goUpdates issue create test mocks for milestone resolver method.
internal/service/interfaces.goAdds MilestoneServiceInterface.
internal/service/client_interfaces.goAdds milestone ops interface and resolver method to client interfaces.
internal/format/text_renderer.goRenders milestone info for issues and adds milestone text renderers.
internal/format/renderer.goExtends renderer interface with milestone render methods.
internal/format/json_renderer.goAdds milestone JSON rendering entry points.
internal/format/json_dtos.goAdds milestone DTOs and includes milestone info in issue DTOs.
internal/format/issue.goAdds milestone line to issue body rendering.
internal/format/format.goAdds formatter methods for milestone render/list render.
internal/format/format_test.goAdds tests for milestone text+JSON formatting.
internal/cli/root.goRegisters milestones command and updates help text for -m.
internal/cli/milestones.goNew cobra command group for milestones CRUD/list/get.
internal/cli/issues.goAdds --milestone/-m to issues list/create/update flags and wiring.
internal/cli/dependencies.goExposes milestone service via CLI dependencies.
CLAUDE.mdUpdates user-facing docs/examples to include milestones and --milestone.
CHANGELOG.mdNotes new milestone commands, flags, and output changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadpkg/linear/resolver.go
Comment threadpkg/linear/resolver.go
Comment threadinternal/format/text_renderer.go
@torarnv

torarnv commented Aug 9, 2026

Copy link
Copy Markdown

This looks like a nice addition. Anything blocking its merge? @joa23

Might need a rebase @martin-piliar

Sign up for freeto 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.

3 participants

@martin-piliar@torarnv