diff --git a/commands/issue.go b/commands/issue.go index cdc7cbfc..bfd42743 100644 --- a/commands/issue.go +++ b/commands/issue.go @@ -2,13 +2,14 @@ package commands import ( "fmt" + "strings" + "github.com/gookit/color" "github.com/gosuri/uitable" "github.com/spf13/cobra" "github.com/xanzy/go-gitlab" "glab/internal/git" - "glab/internal/manip" - "strings" + "glab/internal/utils" ) func displayAllIssues(m []*gitlab.Issue) { @@ -26,7 +27,7 @@ func displayAllIssues(m []*gitlab.Issue) { labels = "(" + labels + ")" } var issueID string - duration := manip.TimeAgo(*issue.CreatedAt) + duration := utils.TimeToPrettyTimeAgo(*issue.CreatedAt) if issue.State == "opened" { issueID = color.Sprintf("#%d", issue.IID) } else { @@ -41,7 +42,7 @@ func displayAllIssues(m []*gitlab.Issue) { } func displayIssue(hm *gitlab.Issue) { - duration := manip.TimeAgo(*hm.CreatedAt) + duration := utils.TimeToPrettyTimeAgo(*hm.CreatedAt) if hm.State == "opened" { color.Printf("#%d %s (%s)\n", hm.IID, hm.Title, duration) } else { diff --git a/commands/issue_note_create.go b/commands/issue_note_create.go new file mode 100644 index 00000000..9afdb5bd --- /dev/null +++ b/commands/issue_note_create.go @@ -0,0 +1,69 @@ +package commands + + +import ( + "fmt" + "github.com/AlecAivazis/survey/v2" + "glab/internal/git" + "glab/internal/manip" + "log" + + "github.com/spf13/cobra" + gitlab "github.com/xanzy/go-gitlab" +) + +var issueCreateNoteCmd = &cobra.Command{ + Use: "note ", + Aliases: []string{"comment"}, + Short: "Add a comment to issue", + Long: ``, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + + gitlabClient, repo := git.InitGitlabClient() + mID := args[0] + body, err := cmd.Flags().GetString("message") + if r, _ := cmd.Flags().GetString("repo"); r != "" { + repo = r + } + if err != nil { + er(err) + return + } + mr, _, err := gitlabClient.Issues.GetIssue(repo, manip.StringToInt(mID)) + if err != nil { + er(err) + return + } + if body == "" { + prompt := &survey.Editor{ + Renderer: survey.Renderer{}, + Message: "Note Message: ", + Help: "Enter the note message for issue. Uses the editor defined by the $VISUAL or $EDITOR environment variables). If neither of those are present, notepad (on Windows) or vim (Linux or Mac) is used", + FileName: "*.md", + } + err = survey.AskOne(prompt, &body) + } + + if err != nil { + er(err) + return + } + if body == "" { + log.Fatal("Aborted... Note has an empty message") + } + + noteInfo,_, err := gitlabClient.Notes.CreateIssueNote(repo, manip.StringToInt(mID), &gitlab.CreateIssueNoteOptions{ + Body: &body, + }) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s#note_%d\n",mr.WebURL, noteInfo.ID) + }, +} + +func init() { + issueCreateNoteCmd.Flags().StringP("message", "m", "", "Enter note message") + issueCmd.AddCommand(issueCreateNoteCmd) +} \ No newline at end of file diff --git a/commands/mr.go b/commands/mr.go index 01090c20..ed3db46d 100644 --- a/commands/mr.go +++ b/commands/mr.go @@ -7,11 +7,11 @@ import ( "github.com/spf13/cobra" "github.com/xanzy/go-gitlab" "glab/internal/git" - "glab/internal/manip" + "glab/internal/utils" ) func displayMergeRequest(hm *gitlab.MergeRequest) { - duration := manip.TimeAgo(*hm.CreatedAt) + duration := utils.TimeToPrettyTimeAgo(*hm.CreatedAt) if hm.State == "opened" { color.Printf("#%d %s (%s) %s\n", hm.IID, hm.Title, hm.SourceBranch, duration) } else { diff --git a/commands/mr_note_create.go b/commands/mr_note_create.go new file mode 100644 index 00000000..678bff2a --- /dev/null +++ b/commands/mr_note_create.go @@ -0,0 +1,69 @@ +package commands + + +import ( + "fmt" + "github.com/AlecAivazis/survey/v2" + "glab/internal/git" + "glab/internal/manip" + "log" + + "github.com/spf13/cobra" + gitlab "github.com/xanzy/go-gitlab" +) + +var mrCreateNoteCmd = &cobra.Command{ + Use: "note ", + Aliases: []string{"comment"}, + Short: "Add a comment to merge request", + Long: ``, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + + gitlabClient, repo := git.InitGitlabClient() + mID := args[0] + body, err := cmd.Flags().GetString("message") + if r, _ := cmd.Flags().GetString("repo"); r != "" { + repo = r + } + if err != nil { + er(err) + return + } + mr, _, err := gitlabClient.MergeRequests.GetMergeRequest(repo, manip.StringToInt(mID), &gitlab.GetMergeRequestsOptions{}) + if err != nil { + er(err) + return + } + if body == "" { + prompt := &survey.Editor{ + Renderer: survey.Renderer{}, + Message: "Note Message: ", + Help: "Enter the note message for the merge request. Uses the editor defined by the $VISUAL or $EDITOR environment variables). If neither of those are present, notepad (on Windows) or vim (Linux or Mac) is used", + FileName: "*.md", + } + err = survey.AskOne(prompt, &body) + } + + if err != nil { + er(err) + return + } + if body == "" { + log.Fatal("Aborted... Note has an empty message") + } + + noteInfo,_, err := gitlabClient.Notes.CreateMergeRequestNote(repo, manip.StringToInt(mID), &gitlab.CreateMergeRequestNoteOptions{ + Body: &body, + }) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s#note_%d\n",mr.WebURL, noteInfo.ID) + }, +} + +func init() { + mrCreateNoteCmd.Flags().StringP("message", "m", "", "Use the given ; multiple -m are concatenated as separate paragraphs") + mrCmd.AddCommand(mrCreateNoteCmd) +} \ No newline at end of file diff --git a/commands/mr_show.go b/commands/mr_show.go deleted file mode 100644 index a971eb68..00000000 --- a/commands/mr_show.go +++ /dev/null @@ -1,20 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" -) - -var mrBrowseCmd = &cobra.Command{ - Use: "browse [help]", - Aliases: []string{"b"}, - Short: "View merge request in a browser", - Long: ``, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - - }, -} - -func init() { - mrCmd.AddCommand(mrBrowseCmd) -} diff --git a/commands/mr_view.go b/commands/mr_view.go new file mode 100644 index 00000000..795338c1 --- /dev/null +++ b/commands/mr_view.go @@ -0,0 +1,151 @@ +package commands + +import ( + "fmt" + "github.com/MakeNowJust/heredoc" + "github.com/gookit/color" + "github.com/gosuri/uitable" + "github.com/spf13/cobra" + "github.com/xanzy/go-gitlab" + "glab/internal/browser" + "glab/internal/git" + "glab/internal/manip" + "glab/internal/utils" + "log" + "strings" + "time" +) + +var mrViewCmd = &cobra.Command{ + Use: "view ", + Short: `Display the title, body, and other information about a merge request.`, + Long: ``, + Aliases: []string{"show"}, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 || len(args) > 1 { + cmdErr(cmd, args) + return + } + pid := manip.StringToInt(args[0]) + + gitlabClient, repo := git.InitGitlabClient() + + if r, _ := cmd.Flags().GetString("repo"); r != "" { + repo = r + } + opts := &gitlab.GetMergeRequestsOptions{} + opts.IncludeDivergedCommitsCount = gitlab.Bool(true) + opts.RenderHTML = gitlab.Bool(true) + opts.IncludeRebaseInProgress = gitlab.Bool(true) + + mr, _, err := gitlabClient.MergeRequests.GetMergeRequest(repo, pid, opts) + if err != nil { + log.Fatal(err) + } + if lb, _ := cmd.Flags().GetBool("web"); lb { //open in browser if --web flag is specified + a, err := browser.Command(mr.WebURL) + if err != nil { + er(err) + } + if err := a.Run(); err != nil { + er(err) + } + return + } + showSystemLog, _ := cmd.Flags().GetBool("system-logs") + var mrState string + if mr.State == "opened" { + mrState = color.Green.Sprint(mr.State) + } else { + mrState = color.Red.Sprint(mr.State) + } + now := time.Now() + ago := now.Sub(*mr.CreatedAt) + color.Printf("\n%s #%d\n", mr.Title, mr.IID) + color.Printf("(%s) • opened by %s (%s) %s\n", mrState, + mr.Author.Username, + mr.Author.Name, + utils.PrettyTimeAgo(ago), + ) + if mr.Description != "" { + mr.Description, _ = utils.RenderMarkdown(mr.Description) + fmt.Println(mr.Description) + } + color.Printf("\n%d upvotes • %d downvotes • %d comments\n\n", + mr.Upvotes, mr.Downvotes, mr.UserNotesCount) + var labels string + for _, l := range mr.Labels { + labels += " " + l + "," + } + labels = strings.Trim(labels, ", ") + + var assignees string + for _, a := range mr.Assignees { + assignees += " " + a.Username + "(" + a.Name + ")," + } + assignees = strings.Trim(assignees, ", ") + table := uitable.New() + table.MaxColWidth = 50 + table.Wrap = true + table.AddRow("Project ID:", mr.ProjectID) + table.AddRow("Labels:", prettifyNilEmptyValues(labels, "None")) + table.AddRow("Milestone:", prettifyNilEmptyValues(mr.Milestone, "None")) + table.AddRow("Assignees:", prettifyNilEmptyValues(assignees, "None")) + table.AddRow("Discussion Locked:", prettifyNilEmptyValues(mr.DiscussionLocked, "false")) + table.AddRow("Subscribed:", prettifyNilEmptyValues(mr.Subscribed, "false")) + + if mr.State == "closed" { + now := time.Now() + ago := now.Sub(*mr.ClosedAt) + table.AddRow("Closed By:", + fmt.Sprintf("%s (%s) %s", mr.ClosedBy.Username, mr.ClosedBy.Name, utils.PrettyTimeAgo(ago))) + } + table.AddRow("Web URL:", mr.WebURL) + fmt.Println(table) + fmt.Println() // Empty Space + + if c, _ := cmd.Flags().GetBool("comments"); c { + l := &gitlab.ListMergeRequestNotesOptions{} + notes, _, err := gitlabClient.Notes.ListMergeRequestNotes(repo, pid, l) + if err != nil { + er(err) + } + + table := uitable.New() + table.MaxColWidth = 100 + table.Wrap = true + fmt.Println(heredoc.Doc(` + -------------------------------------------- + Comments / Notes + -------------------------------------------- + `)) + if len(notes) > 0 { + for _, note := range notes { + if note.System && !showSystemLog { + continue + } + //body, _ := utils.RenderMarkdown(note.Body) + table.AddRow(note.Author.Username+":", + fmt.Sprintf("%s\n%s", + note.Body, + color.Gray.Sprint(utils.TimeToPrettyTimeAgo(*note.CreatedAt)), + ), + ) + table.AddRow("") + } + fmt.Println(table) + } else { + fmt.Println("There are no comments on this mr") + } + } + }, +} + +func init() { + mrViewCmd.Flags().StringP("repo", "r", "", "Select another repository using the OWNER/REPO format. Supports group namespaces") + mrViewCmd.Flags().BoolP("comments", "c", false, "Show mr comments and activities") + mrViewCmd.Flags().BoolP("system-logs", "s", false, "Show system activities / logs") + mrViewCmd.Flags().BoolP("web", "w", false, "Open mr in a browser. Uses default browser or browser specified in BROWSER variable") + mrCmd.AddCommand(mrViewCmd) +} diff --git a/commands/pipeline.go b/commands/pipeline.go index abe32b13..e9b6a802 100644 --- a/commands/pipeline.go +++ b/commands/pipeline.go @@ -3,6 +3,7 @@ package commands import ( "errors" "fmt" + "glab/internal/utils" "io" "math" "os" @@ -12,7 +13,6 @@ import ( "github.com/spf13/cobra" "github.com/xanzy/go-gitlab" "glab/internal/git" - "glab/internal/manip" ) func displayMultiplePipelines(m []*gitlab.PipelineInfo) { @@ -26,7 +26,7 @@ func displayMultiplePipelines(m []*gitlab.PipelineInfo) { if len(m) > 0 { fmt.Printf("Showing pipelines %d of %d on %s\n\n", len(m), len(m), git.GetRepo()) for _, pipeline := range m { - duration := manip.TimeAgo(*pipeline.CreatedAt) + duration := utils.TimeToPrettyTimeAgo(*pipeline.CreatedAt) var pipeState string if pipeline.Status == "success" { pipeState = color.Sprintf("(%s) • #%d", pipeline.Status, pipeline.ID)