commands/issue/update/issue_update.go (180 lines of code) (raw):
package update
import (
"errors"
"fmt"
"strings"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/issue/issueutils"
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"
gitlab "gitlab.com/gitlab-org/api/client-go"
)
func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
issueUpdateCmd := &cobra.Command{
Use: "update <id>",
Short: `Update issue`,
Long: ``,
Example: heredoc.Doc(`
- glab issue update 42 --label ui,ux
- glab issue update 42 --unlabel working
`),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var err error
var actions []string
var ua *cmdutils.UserAssignments
out := f.IO.StdOut
c := f.IO.Color()
if cmd.Flags().Changed("unassign") && cmd.Flags().Changed("assignee") {
return &cmdutils.FlagError{Err: fmt.Errorf("--assignee and --unassign are mutually exclusive.")}
}
// Parse assignees early so we can fail early in case of conflicts
if cmd.Flags().Changed("assignee") {
givenAssignees, err := cmd.Flags().GetStringSlice("assignee")
if err != nil {
return err
}
ua = cmdutils.ParseAssignees(givenAssignees)
err = ua.VerifyAssignees()
if err != nil {
return &cmdutils.FlagError{Err: fmt.Errorf("--assignee: %w", err)}
}
}
if cmd.Flags().Changed("lock-discussion") && cmd.Flags().Changed("unlock-discussion") {
return &cmdutils.FlagError{
Err: errors.New("--lock-discussion and --unlock-discussion can't be used together."),
}
}
if cmd.Flags().Changed("confidential") && cmd.Flags().Changed("public") {
return &cmdutils.FlagError{Err: errors.New("--public and --confidential can't be used together.")}
}
apiClient, err := f.HttpClient()
if err != nil {
return err
}
issue, repo, err := issueutils.IssueFromArg(apiClient, f.BaseRepo, args[0])
if err != nil {
return err
}
l := &gitlab.UpdateIssueOptions{}
if m, _ := cmd.Flags().GetString("title"); m != "" {
actions = append(actions, fmt.Sprintf("updated title to %q", m))
l.Title = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetBool("lock-discussion"); m {
actions = append(actions, "locked discussion")
l.DiscussionLocked = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetBool("unlock-discussion"); m {
actions = append(actions, "unlocked dicussion")
l.DiscussionLocked = gitlab.Ptr(false)
}
if cmd.Flags().Changed("weight") {
weight, _ := cmd.Flags().GetInt("weight")
if weight < 0 {
return &cmdutils.FlagError{Err: errors.New("weight must be a positive integer or zero")}
}
actions = append(actions, fmt.Sprintf("set weight to %d", weight))
l.Weight = gitlab.Ptr(weight)
}
if m, _ := cmd.Flags().GetString("description"); m != "" {
actions = append(actions, "updated description")
// Edit the description via editor
if m == "-" {
// Fetch the current issue and description
apiClient, err := f.HttpClient()
if err != nil {
return err
}
issue, _, err := issueutils.IssueFromArg(apiClient, f.BaseRepo, args[0])
if err != nil {
return err
}
editor, err := cmdutils.GetEditor(f.Config)
if err != nil {
return err
}
l.Description = gitlab.Ptr("")
err = cmdutils.EditorPrompt(l.Description, "Description", issue.Description, editor)
if err != nil {
return err
}
} else {
l.Description = gitlab.Ptr(m)
}
}
if m, _ := cmd.Flags().GetStringSlice("label"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("added labels %s", strings.Join(m, " ")))
l.AddLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetStringSlice("unlabel"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("removed labels %s", strings.Join(m, " ")))
l.RemoveLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetBool("public"); m {
actions = append(actions, "made public")
l.Confidential = gitlab.Ptr(false)
}
if m, _ := cmd.Flags().GetBool("confidential"); m {
actions = append(actions, "made confidential")
l.Confidential = gitlab.Ptr(true)
}
if ok := cmd.Flags().Changed("milestone"); ok {
if m, _ := cmd.Flags().GetString("milestone"); m != "" || m == "0" {
mID, err := cmdutils.ParseMilestone(apiClient, repo, m)
if err != nil {
return err
}
actions = append(actions, fmt.Sprintf("added milestone %q", m))
l.MilestoneID = gitlab.Ptr(mID)
} else {
// Unassign the Milestone
actions = append(actions, "unassigned milestone")
l.MilestoneID = gitlab.Ptr(0)
}
}
if cmd.Flags().Changed("unassign") {
l.AssigneeIDs = &[]int{0} // 0 or an empty int[] is the documented way to unassign
actions = append(actions, "unassigned all users")
}
if ua != nil {
if len(ua.ToReplace) != 0 {
l.AssigneeIDs, actions, err = ua.UsersFromReplaces(apiClient, actions)
if err != nil {
return err
}
} else if len(ua.ToAdd) != 0 || len(ua.ToRemove) != 0 {
issue, err := api.GetIssue(apiClient, repo.FullName(), issue.IID)
if err != nil {
return err
}
l.AssigneeIDs, actions, err = ua.UsersFromAddRemove(issue.Assignees, nil, apiClient, actions)
if err != nil {
return err
}
}
}
fmt.Fprintf(out, "- Updating issue #%d\n", issue.IID)
issue, err = api.UpdateIssue(apiClient, repo.FullName(), issue.IID, l)
if err != nil {
return err
}
for _, s := range actions {
fmt.Fprintln(out, c.GreenCheck(), s)
}
fmt.Fprintln(out, issueutils.DisplayIssue(c, issue, f.IO.IsaTTY))
return nil
},
}
issueUpdateCmd.Flags().StringP("title", "t", "", "Title of issue.")
issueUpdateCmd.Flags().BoolP("lock-discussion", "", false, "Lock discussion on issue.")
issueUpdateCmd.Flags().BoolP("unlock-discussion", "", false, "Unlock discussion on issue.")
issueUpdateCmd.Flags().StringP("description", "d", "", "Issue description. Set to \"-\" to open an editor.")
issueUpdateCmd.Flags().StringSliceP("label", "l", []string{}, "Add labels.")
issueUpdateCmd.Flags().StringSliceP("unlabel", "u", []string{}, "Remove labels.")
issueUpdateCmd.Flags().BoolP("public", "p", false, "Make issue public.")
issueUpdateCmd.Flags().BoolP("confidential", "c", false, "Make issue confidential")
issueUpdateCmd.Flags().StringP("milestone", "m", "", "Title of the milestone to assign Set to \"\" or 0 to unassign.")
issueUpdateCmd.Flags().
StringSliceP("assignee", "a", []string{}, "Assign users by username. Prefix with '!' or '-' to remove from existing assignees, or '+' to add new. Otherwise, replace existing assignees with these users.")
issueUpdateCmd.Flags().Bool("unassign", false, "Unassign all users.")
issueUpdateCmd.Flags().IntP("weight", "w", 0, "Set weight of the issue.")
return issueUpdateCmd
}