fix(milestone): address milestones by title or ID everywhere

milestone view v2.0 failed with "invalid resource number" although its
usage promised <id-or-name>, and issue create --milestone v1.0 failed
with a strconv error. Every milestone argument (view, edit, delete,
close, reopen, milestone issue add|remove|list) and issue create|edit
-m/--milestone now accept a title or an ID: a number is an ID first,
then a title; --by-name matches numeric titles only. --milestone-name
stays as a hidden name of --milestone, and issue edit gains
--remove-milestone (as does --milestone 0).

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-12 00:14:30 +02:00
1 parent 0d013746b5
commit 1035ff551b
12 files changed
+220 -147

No files matched your search

+14 -12
View File
@@ -20,8 +20,8 @@ func (a *application) issueEditCommand() *cobra.Command {
var useEditor bool
var deadline string
var ref string
var milestone int64
var milestoneName string
var milestone string
var removeMilestone bool
var metadata metadataFlags
cmd := &cobra.Command{Use: "edit <number>...", Short: "Edit issue content, assignees, and milestone", Args: usageArgs(cobra.MinimumNArgs(1)), RunE: func(cmd *cobra.Command, args []string) (runErr error) {
var draft terminal.Draft
@@ -46,10 +46,14 @@ func (a *application) issueEditCommand() *cobra.Command {
if useEditor && len(numbers) != 1 {
return clierr.Wrap(clierr.Usage, errors.New("--editor requires one issue"))
}
if err := validateMilestoneFlags(cmd, milestoneName, milestone); err != nil {
milestone, removeMilestone, err := milestoneFlag(cmd, milestone)
if err != nil {
return err
}
opts := services.IssueEdit{}
if removeMilestone {
opts.Milestone = new(int64)
}
if cmd.Flags().Changed("ref") {
opts.Ref = &ref
}
@@ -72,25 +76,22 @@ func (a *application) issueEditCommand() *cobra.Command {
}
opts.Body = &body
}
if cmd.Flags().Changed("milestone") {
opts.Milestone = &milestone
}
if err := metadata.validate(cmd); err != nil {
return err
}
if opts == (services.IssueEdit{}) && !useEditor && !metadata.changed(cmd) && !cmd.Flags().Changed("milestone-name") {
if opts == (services.IssueEdit{}) && !useEditor && !metadata.changed(cmd) && milestone == "" {
return clierr.Wrap(clierr.Usage, errors.New("supply an edit flag; see tea issue edit --help"))
}
target, err := a.resolve(cmd.Context(), true)
if err != nil {
return err
}
if cmd.Flags().Changed("milestone-name") {
milestone, err = (services.Milestones{Client: target.client, Repository: target.Repo}).ResolveName(cmd.Context(), milestoneName)
if milestone != "" {
id, err := milestoneID(cmd, target, milestone)
if err != nil {
return err
}
opts.Milestone = &milestone
opts.Milestone = &id
}
if opts.Labels, opts.Assignees, opts.Changes, err = metadata.resolve(cmd, target); err != nil {
return err
@@ -117,8 +118,9 @@ func (a *application) issueEditCommand() *cobra.Command {
cmd.Flags().StringVar(&body, "body", "", "Issue body (empty clears)")
cmd.Flags().StringVar(&file, "body-file", "", "Read body from file, or - for stdin")
cmd.Flags().BoolVar(&useEditor, "editor", false, "Edit the current issue body in the configured editor")
cmd.Flags().StringVar(&milestoneName, "milestone-name", "", "Milestone by exact title; conflicts with --milestone")
cmd.Flags().Int64Var(&milestone, "milestone", 0, "Milestone ID; 0 clears")
cmd.Flags().StringVarP(&milestone, "milestone", "m", "", "Move the issue to a milestone by `title` or ID")
cmd.Flags().BoolVar(&removeMilestone, "remove-milestone", false, "Remove the issue from its milestone")
flagAliases(cmd, map[string]string{"milestone-name": "milestone"})
metadata.register(cmd)
return cmd
}