2020-09-29 05:55:34 +00:00
package update
import (
2020-12-23 16:19:55 +00:00
"errors"
2020-09-29 05:55:34 +00:00
"fmt"
"strings"
2022-09-19 20:23:45 +00:00
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/mr/mrutils"
2020-09-29 05:55:34 +00:00
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
)
func NewCmdUpdate ( f * cmdutils . Factory ) * cobra . Command {
var mrUpdateCmd = & cobra . Command {
2020-10-26 17:37:21 +00:00
Use : "update [<id> | <branch>]" ,
2020-09-29 05:55:34 +00:00
Short : ` Update merge requests ` ,
Long : ` ` ,
Example : heredoc . Doc ( `
2022-10-21 14:38:48 +00:00
glab mr update 23 -- ready
glab mr update 23 -- draft
glab mr update -- draft # Updates MR related to current branch
2020-09-29 05:55:34 +00:00
` ) ,
2020-10-14 15:09:20 +00:00
Args : cobra . MaximumNArgs ( 1 ) ,
2020-09-29 05:55:34 +00:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
var err error
2020-12-31 07:17:51 +00:00
var actions [ ] string
2021-04-30 06:08:22 +00:00
var ua * cmdutils . UserAssignments // assignees
var ur * cmdutils . UserAssignments // reviewers
2021-01-29 00:56:45 +00:00
c := f . IO . Color ( )
2020-12-31 14:51:49 +00:00
2021-01-17 19:48:59 +00:00
if cmd . Flags ( ) . Changed ( "unassign" ) && cmd . Flags ( ) . Changed ( "assignee" ) {
return & cmdutils . FlagError { Err : fmt . Errorf ( "--assignee and --unassign are mutually exclusive" ) }
2021-01-05 10:31:32 +00:00
}
2020-12-31 14:51:49 +00:00
// 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
}
2021-01-01 12:20:56 +00:00
ua = cmdutils . ParseAssignees ( givenAssignees )
2020-12-31 14:51:49 +00:00
2021-01-01 12:20:56 +00:00
err = ua . VerifyAssignees ( )
if err != nil {
return & cmdutils . FlagError { Err : fmt . Errorf ( "--assignee: %w" , err ) }
2020-12-31 14:51:49 +00:00
}
}
2020-10-09 16:04:06 +00:00
2021-04-27 20:12:32 +00:00
if cmd . Flags ( ) . Changed ( "reviewer" ) {
givenReviewers , err := cmd . Flags ( ) . GetStringSlice ( "reviewer" )
if err != nil {
return err
}
ur = cmdutils . ParseAssignees ( givenReviewers )
2021-04-30 06:08:22 +00:00
ur . AssignmentType = cmdutils . ReviewerAssignment
2021-04-27 20:12:32 +00:00
err = ur . VerifyAssignees ( )
if err != nil {
return & cmdutils . FlagError { Err : fmt . Errorf ( "--reviewer: %w" , err ) }
}
}
2020-12-23 16:19:55 +00:00
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" ) }
}
2020-09-29 05:55:34 +00:00
apiClient , err := f . HttpClient ( )
if err != nil {
return err
}
2020-10-09 16:04:06 +00:00
2021-02-18 01:22:14 +00:00
mr , repo , err := mrutils . MRFromArgs ( f , args , "any" )
2020-09-29 05:55:34 +00:00
if err != nil {
return err
}
l := & gitlab . UpdateMergeRequestOptions { }
var mergeTitle string
isDraft , _ := cmd . Flags ( ) . GetBool ( "draft" )
isWIP , _ := cmd . Flags ( ) . GetBool ( "wip" )
if m , _ := cmd . Flags ( ) . GetString ( "title" ) ; m != "" {
2020-12-31 07:17:51 +00:00
actions = append ( actions , fmt . Sprintf ( "updated title to %q" , m ) )
2020-09-29 05:55:34 +00:00
mergeTitle = m
}
if mergeTitle == "" {
opts := & gitlab . GetMergeRequestsOptions { }
2020-10-14 15:09:20 +00:00
mr , err := api . GetMR ( apiClient , repo . FullName ( ) , mr . IID , opts )
2020-09-29 05:55:34 +00:00
if err != nil {
return err
}
mergeTitle = mr . Title
}
if isDraft || isWIP {
if isDraft {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "marked as Draft" )
2020-09-29 05:55:34 +00:00
mergeTitle = "Draft: " + mergeTitle
} else {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "marked as WIP" )
2020-09-29 05:55:34 +00:00
mergeTitle = "WIP: " + mergeTitle
}
} else if isReady , _ := cmd . Flags ( ) . GetBool ( "ready" ) ; isReady {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "marked as ready" )
2020-09-29 05:55:34 +00:00
mergeTitle = strings . TrimPrefix ( mergeTitle , "Draft:" )
mergeTitle = strings . TrimPrefix ( mergeTitle , "draft:" )
mergeTitle = strings . TrimPrefix ( mergeTitle , "DRAFT:" )
mergeTitle = strings . TrimPrefix ( mergeTitle , "WIP:" )
mergeTitle = strings . TrimPrefix ( mergeTitle , "wip:" )
mergeTitle = strings . TrimPrefix ( mergeTitle , "Wip:" )
mergeTitle = strings . TrimSpace ( mergeTitle )
}
2020-10-14 15:09:20 +00:00
2020-09-29 05:55:34 +00:00
l . Title = gitlab . String ( mergeTitle )
if m , _ := cmd . Flags ( ) . GetBool ( "lock-discussion" ) ; m {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "locked discussion" )
2020-09-29 05:55:34 +00:00
l . DiscussionLocked = gitlab . Bool ( m )
}
2020-12-23 16:19:55 +00:00
if m , _ := cmd . Flags ( ) . GetBool ( "unlock-discussion" ) ; m {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "unlocked discussion" )
2020-12-23 16:19:55 +00:00
l . DiscussionLocked = gitlab . Bool ( false )
}
2020-10-14 15:09:20 +00:00
2020-09-29 05:55:34 +00:00
if m , _ := cmd . Flags ( ) . GetString ( "description" ) ; m != "" {
2020-12-31 07:17:51 +00:00
actions = append ( actions , "updated description" )
2020-09-29 05:55:34 +00:00
l . Description = gitlab . String ( m )
}
2020-12-31 17:00:59 +00:00
2020-12-31 16:46:21 +00:00
if m , _ := cmd . Flags ( ) . GetStringSlice ( "label" ) ; len ( m ) != 0 {
2020-12-31 17:00:59 +00:00
actions = append ( actions , fmt . Sprintf ( "added labels %s" , strings . Join ( m , " " ) ) )
2022-10-04 19:29:02 +00:00
l . AddLabels = ( * gitlab . Labels ) ( & m )
2020-12-31 17:00:59 +00:00
}
2020-12-31 16:46:21 +00:00
if m , _ := cmd . Flags ( ) . GetStringSlice ( "unlabel" ) ; len ( m ) != 0 {
2020-12-31 17:00:59 +00:00
actions = append ( actions , fmt . Sprintf ( "removed labels %s" , strings . Join ( m , " " ) ) )
2022-10-04 19:29:02 +00:00
l . RemoveLabels = ( * gitlab . Labels ) ( & m )
2020-12-31 17:00:59 +00:00
}
2021-01-18 11:55:25 +00:00
if m , _ := cmd . Flags ( ) . GetString ( "target-branch" ) ; m != "" {
actions = append ( actions , fmt . Sprintf ( "set target branch to %q" , m ) )
l . TargetBranch = gitlab . String ( m )
}
2020-12-31 09:51:20 +00:00
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 . Int ( mID )
} else {
// Unassign the Milestone
actions = append ( actions , "unassigned milestone" )
l . MilestoneID = gitlab . Int ( 0 )
}
}
2021-01-17 19:54:34 +00:00
if cmd . Flags ( ) . Changed ( "unassign" ) {
2022-10-04 19:29:02 +00:00
l . AssigneeIDs = & [ ] int { 0 } // 0 or an empty int[] is the documented way to unassign
2021-01-17 19:54:34 +00:00
actions = append ( actions , "unassigned all users" )
}
2021-01-01 12:20:56 +00:00
if ua != nil {
if len ( ua . ToReplace ) != 0 {
l . AssigneeIDs , actions , err = ua . UsersFromReplaces ( apiClient , actions )
if err != nil {
return err
2020-12-31 14:51:49 +00:00
}
2021-01-01 12:20:56 +00:00
} else if len ( ua . ToAdd ) != 0 || len ( ua . ToRemove ) != 0 {
l . AssigneeIDs , actions , err = ua . UsersFromAddRemove ( nil , mr . Assignees , apiClient , actions )
2020-12-31 14:51:49 +00:00
if err != nil {
return err
}
}
}
2021-01-01 12:20:56 +00:00
2021-04-27 20:12:32 +00:00
if ur != nil {
if len ( ur . ToReplace ) != 0 {
l . ReviewerIDs , actions , err = ur . UsersFromReplaces ( apiClient , actions )
if err != nil {
return err
}
} else if len ( ur . ToAdd ) != 0 || len ( ur . ToRemove ) != 0 {
l . ReviewerIDs , actions , err = ur . UsersFromAddRemove ( nil , mr . Reviewers , apiClient , actions )
if err != nil {
return err
}
}
}
2020-10-25 11:09:46 +00:00
if removeSource , _ := cmd . Flags ( ) . GetBool ( "remove-source-branch" ) ; removeSource {
2022-09-14 20:39:52 +00:00
if mr . ForceRemoveSourceBranch {
actions = append ( actions , "disabled removal of source branch on merge" )
} else {
actions = append ( actions , "enabled removal of source branch on merge" )
}
l . RemoveSourceBranch = gitlab . Bool ( ! mr . ForceRemoveSourceBranch )
2020-10-25 11:09:46 +00:00
}
2021-10-04 07:00:07 +00:00
if squashBeforeMerge , _ := cmd . Flags ( ) . GetBool ( "squash-before-merge" ) ; squashBeforeMerge {
2021-10-03 18:33:26 +00:00
2021-10-04 07:00:07 +00:00
if mr . Squash {
actions = append ( actions , "disabled squashing of commits before merge" )
2021-10-03 18:33:26 +00:00
} else {
2021-10-04 07:00:07 +00:00
actions = append ( actions , "enabled squashing of commits before merge" )
2021-10-03 18:33:26 +00:00
}
l . Squash = gitlab . Bool ( ! mr . Squash )
}
2020-12-31 07:17:51 +00:00
fmt . Fprintf ( f . IO . StdOut , "- Updating merge request !%d\n" , mr . IID )
2020-10-14 15:09:20 +00:00
mr , err = api . UpdateMR ( apiClient , repo . FullName ( ) , mr . IID , l )
2020-09-29 05:55:34 +00:00
if err != nil {
return err
}
2020-12-31 07:17:51 +00:00
for _ , s := range actions {
2021-01-29 00:56:45 +00:00
fmt . Fprintln ( f . IO . StdOut , c . GreenCheck ( ) , s )
2020-12-31 07:17:51 +00:00
}
2021-11-18 14:47:03 +00:00
fmt . Fprintln ( f . IO . StdOut , mrutils . DisplayMR ( c , mr , f . IO . IsaTTY ) )
2020-09-29 05:55:34 +00:00
return nil
} ,
}
mrUpdateCmd . Flags ( ) . BoolP ( "draft" , "" , false , "Mark merge request as a draft" )
mrUpdateCmd . Flags ( ) . BoolP ( "ready" , "r" , false , "Mark merge request as ready to be reviewed and merged" )
mrUpdateCmd . Flags ( ) . BoolP ( "wip" , "" , false , "Mark merge request as a work in progress. Alternative to --draft" )
mrUpdateCmd . Flags ( ) . StringP ( "title" , "t" , "" , "Title of merge request" )
mrUpdateCmd . Flags ( ) . BoolP ( "lock-discussion" , "" , false , "Lock discussion on merge request" )
2020-12-23 16:19:55 +00:00
mrUpdateCmd . Flags ( ) . BoolP ( "unlock-discussion" , "" , false , "Unlock discussion on merge request" )
2020-09-29 05:55:34 +00:00
mrUpdateCmd . Flags ( ) . StringP ( "description" , "d" , "" , "merge request description" )
2020-12-31 17:00:59 +00:00
mrUpdateCmd . Flags ( ) . StringSliceP ( "label" , "l" , [ ] string { } , "add labels" )
mrUpdateCmd . Flags ( ) . StringSliceP ( "unlabel" , "u" , [ ] string { } , "remove labels" )
2020-12-31 14:51:49 +00:00
mrUpdateCmd . Flags ( ) . StringSliceP ( "assignee" , "a" , [ ] string { } , "assign users via username, prefix with '!' or '-' to remove from existing assignees, '+' to add, otherwise replace existing assignees with given users" )
2021-04-30 06:08:22 +00:00
mrUpdateCmd . Flags ( ) . StringSliceP ( "reviewer" , "" , [ ] string { } , "request review from users by their usernames, prefix with '!' or '-' to remove from existing reviewers, '+' to add, otherwise replace existing reviewers with given users" )
2021-01-05 10:31:32 +00:00
mrUpdateCmd . Flags ( ) . Bool ( "unassign" , false , "unassign all users" )
2021-10-04 07:00:07 +00:00
mrUpdateCmd . Flags ( ) . BoolP ( "squash-before-merge" , "" , false , "Toggles the option to squash commits into a single commit when merging" )
2022-09-14 20:39:52 +00:00
mrUpdateCmd . Flags ( ) . BoolP ( "remove-source-branch" , "" , false , "Toggles the removal of the Source Branch on merge" )
2020-12-31 09:51:20 +00:00
mrUpdateCmd . Flags ( ) . StringP ( "milestone" , "m" , "" , "title of the milestone to assign, pass \"\" or 0 to unassign" )
2021-01-18 11:55:25 +00:00
mrUpdateCmd . Flags ( ) . String ( "target-branch" , "" , "set target branch" )
2020-09-29 05:55:34 +00:00
return mrUpdateCmd
}