diff --git a/cmd/issue_note.go b/cmd/issue_note.go index e717fbd3..eea3fc04 100644 --- a/cmd/issue_note.go +++ b/cmd/issue_note.go @@ -1,22 +1,13 @@ package cmd import ( - "bytes" "fmt" - "io/ioutil" "log" "os" - "runtime" - "strconv" - "strings" - "text/template" "github.com/rsteube/carapace" "github.com/spf13/cobra" - gitlab "github.com/xanzy/go-gitlab" "github.com/zaquestion/lab/internal/action" - "github.com/zaquestion/lab/internal/git" - lab "github.com/zaquestion/lab/internal/gitlab" ) var issueNoteCmd = &cobra.Command{ @@ -100,217 +91,6 @@ func NoteRunFn(cmd *cobra.Command, args []string) { createNote(rn, isMR, int(idNum), msgs, filename, linebreak) } -func createNote(rn string, isMR bool, idNum int, msgs []string, filename string, linebreak bool) { - - var err error - - body := "" - if filename != "" { - content, err := ioutil.ReadFile(filename) - if err != nil { - log.Fatal(err) - } - body = string(content) - } else { - if isMR { - mr, err := lab.MRGet(rn, idNum) - if err != nil { - log.Fatal(err) - } - - state := map[string]string{ - "opened": "OPEN", - "closed": "CLOSED", - "merged": "MERGED", - }[mr.State] - - body = fmt.Sprintf("\n# This comment is being applied to %s Merge Request %d.", state, idNum) - } else { - issue, err := lab.IssueGet(rn, idNum) - if err != nil { - log.Fatal(err) - } - - state := map[string]string{ - "opened": "OPEN", - "closed": "CLOSED", - }[issue.State] - - body = fmt.Sprintf("\n# This comment is being applied to %s Issue %d.", state, idNum) - } - - body, err = noteMsg(msgs, isMR, body) - if err != nil { - _, f, l, _ := runtime.Caller(0) - log.Fatal(f+":"+strconv.Itoa(l)+" ", err) - } - } - - if body == "" { - log.Fatal("aborting note due to empty note msg") - } - - if linebreak { - body = textToMarkdown(body) - } - - var ( - noteURL string - ) - - if isMR { - noteURL, err = lab.MRCreateNote(rn, idNum, &gitlab.CreateMergeRequestNoteOptions{ - Body: &body, - }) - } else { - noteURL, err = lab.IssueCreateNote(rn, idNum, &gitlab.CreateIssueNoteOptions{ - Body: &body, - }) - } - if err != nil { - log.Fatal(err) - } - fmt.Println(noteURL) -} - -func noteMsg(msgs []string, isMR bool, body string) (string, error) { - if len(msgs) > 0 { - return strings.Join(msgs[0:], "\n\n"), nil - } - - text, err := noteText(body) - if err != nil { - return "", err - } - - if isMR { - return git.EditFile("MR_NOTE", text) - } - return git.EditFile("ISSUE_NOTE", text) -} - -func noteText(body string) (string, error) { - const tmpl = `{{.InitMsg}} -{{.CommentChar}} Write a message for this note. Commented lines are discarded.` - - initMsg := body - commentChar := git.CommentChar() - - t, err := template.New("tmpl").Parse(tmpl) - if err != nil { - return "", err - } - - msg := &struct { - InitMsg string - CommentChar string - }{ - InitMsg: initMsg, - CommentChar: commentChar, - } - - var b bytes.Buffer - err = t.Execute(&b, msg) - if err != nil { - return "", err - } - - return b.String(), nil -} - -func replyNote(rn string, isMR bool, idNum int, reply int, quote bool, update bool, filename string, linebreak bool, resolve bool, msgs []string) { - - var ( - discussions []*gitlab.Discussion - err error - NoteURL string - ) - - if isMR { - discussions, err = lab.MRListDiscussions(rn, idNum) - } else { - discussions, err = lab.IssueListDiscussions(rn, idNum) - } - if err != nil { - log.Fatal(err) - } - for _, discussion := range discussions { - for _, note := range discussion.Notes { - - if note.System { - if note.ID == reply { - fmt.Println("ERROR: Cannot reply to note", note.ID) - } - continue - } - - if note.ID != reply { - continue - } - - body := "" - if len(msgs) != 0 { - body, err = noteMsg(msgs, isMR, note.Body) - if err != nil { - _, f, l, _ := runtime.Caller(0) - log.Fatal(f+":"+strconv.Itoa(l)+" ", err) - } - } else if filename != "" { - content, err := ioutil.ReadFile(filename) - if err != nil { - log.Fatal(err) - } - body = string(content) - } else { - noteBody := "" - if quote { - noteBody = note.Body - noteBody = strings.Replace(noteBody, "\n", "\n>", -1) - if !update { - noteBody = ">" + noteBody + "\n" - } - } - body, err = noteMsg([]string{}, isMR, noteBody) - if err != nil { - _, f, l, _ := runtime.Caller(0) - log.Fatal(f+":"+strconv.Itoa(l)+" ", err) - } - } - - if body == "" && !resolve { - log.Fatal("aborting note due to empty note msg") - } - - if linebreak { - body = textToMarkdown(body) - } - - if update { - if isMR { - NoteURL, err = lab.UpdateMRDiscussionNote(rn, idNum, discussion.ID, note.ID, body) - } else { - NoteURL, err = lab.UpdateIssueDiscussionNote(rn, idNum, discussion.ID, note.ID, body) - } - } else { - if isMR { - if body != "" { - NoteURL, err = lab.AddMRDiscussionNote(rn, idNum, discussion.ID, body) - } - if resolve { - NoteURL, err = lab.ResolveMRDiscussion(rn, idNum, discussion.ID, reply) - } - } else { - NoteURL, err = lab.AddIssueDiscussionNote(rn, idNum, discussion.ID, body) - } - } - if err != nil { - log.Fatal(err) - } - fmt.Println(NoteURL) - } - } -} - func init() { issueNoteCmd.Flags().StringArrayP("message", "m", []string{}, "use the given ; multiple -m are concatenated as separate paragraphs") issueNoteCmd.Flags().StringP("file", "F", "", "use the given file as the message") diff --git a/cmd/issue_note_test.go b/cmd/issue_note_test.go index b2b0a519..01d8cb7d 100644 --- a/cmd/issue_note_test.go +++ b/cmd/issue_note_test.go @@ -5,7 +5,6 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -24,36 +23,6 @@ func Test_issueCreateNote(t *testing.T) { require.Contains(t, string(b), "https://gitlab.com/lab-testing/test/issues/1#note_") } -func Test_issueNoteMsg(t *testing.T) { - tests := []struct { - Name string - Msgs []string - ExpectedBody string - }{ - { - Name: "Using messages", - Msgs: []string{"note paragraph 1", "note paragraph 2"}, - ExpectedBody: "note paragraph 1\n\nnote paragraph 2", - }, - { - Name: "From Editor", - Msgs: nil, - ExpectedBody: "", // this is not a great test - }, - } - for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - test := test - t.Parallel() - body, err := noteMsg(test.Msgs, false, "\n") - if err != nil { - t.Fatal(err) - } - assert.Equal(t, test.ExpectedBody, body) - }) - } -} - func Test_issueReplyNote(t *testing.T) { repo := copyTestRepo(t) create := exec.Command(labBinaryPath, "issue", "create", "lab-testing", "-m", "note text") @@ -105,15 +74,3 @@ func Test_issueReplyNote(t *testing.T) { require.Contains(t, string(d), " reply to note") require.Contains(t, string(d), " second reply paragraph") } - -func Test_issueNoteText(t *testing.T) { - t.Parallel() - text, err := noteText("\n") - if err != nil { - t.Fatal(err) - } - require.Equal(t, ` - -# Write a message for this note. Commented lines are discarded.`, text) - -} diff --git a/cmd/note_common.go b/cmd/note_common.go new file mode 100644 index 00000000..6991ec60 --- /dev/null +++ b/cmd/note_common.go @@ -0,0 +1,227 @@ +package cmd + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "runtime" + "strconv" + "strings" + "text/template" + + gitlab "github.com/xanzy/go-gitlab" + "github.com/zaquestion/lab/internal/git" + lab "github.com/zaquestion/lab/internal/gitlab" +) + +func createNote(rn string, isMR bool, idNum int, msgs []string, filename string, linebreak bool) { + + var err error + + body := "" + if filename != "" { + content, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + body = string(content) + } else { + if isMR { + mr, err := lab.MRGet(rn, idNum) + if err != nil { + log.Fatal(err) + } + + state := map[string]string{ + "opened": "OPEN", + "closed": "CLOSED", + "merged": "MERGED", + }[mr.State] + + body = fmt.Sprintf("\n# This comment is being applied to %s Merge Request %d.", state, idNum) + } else { + issue, err := lab.IssueGet(rn, idNum) + if err != nil { + log.Fatal(err) + } + + state := map[string]string{ + "opened": "OPEN", + "closed": "CLOSED", + }[issue.State] + + body = fmt.Sprintf("\n# This comment is being applied to %s Issue %d.", state, idNum) + } + + body, err = noteMsg(msgs, isMR, body) + if err != nil { + _, f, l, _ := runtime.Caller(0) + log.Fatal(f+":"+strconv.Itoa(l)+" ", err) + } + } + + if body == "" { + log.Fatal("aborting note due to empty note msg") + } + + if linebreak { + body = textToMarkdown(body) + } + + var ( + noteURL string + ) + + if isMR { + noteURL, err = lab.MRCreateNote(rn, idNum, &gitlab.CreateMergeRequestNoteOptions{ + Body: &body, + }) + } else { + noteURL, err = lab.IssueCreateNote(rn, idNum, &gitlab.CreateIssueNoteOptions{ + Body: &body, + }) + } + if err != nil { + log.Fatal(err) + } + fmt.Println(noteURL) +} + +func noteMsg(msgs []string, isMR bool, body string) (string, error) { + if len(msgs) > 0 { + return strings.Join(msgs[0:], "\n\n"), nil + } + + text, err := noteText(body) + if err != nil { + return "", err + } + + if isMR { + return git.EditFile("MR_NOTE", text) + } + return git.EditFile("ISSUE_NOTE", text) +} + +func noteText(body string) (string, error) { + const tmpl = `{{.InitMsg}} +{{.CommentChar}} Write a message for this note. Commented lines are discarded.` + + initMsg := body + commentChar := git.CommentChar() + + t, err := template.New("tmpl").Parse(tmpl) + if err != nil { + return "", err + } + + msg := &struct { + InitMsg string + CommentChar string + }{ + InitMsg: initMsg, + CommentChar: commentChar, + } + + var b bytes.Buffer + err = t.Execute(&b, msg) + if err != nil { + return "", err + } + + return b.String(), nil +} + +func replyNote(rn string, isMR bool, idNum int, reply int, quote bool, update bool, filename string, linebreak bool, resolve bool, msgs []string) { + + var ( + discussions []*gitlab.Discussion + err error + NoteURL string + ) + + if isMR { + discussions, err = lab.MRListDiscussions(rn, idNum) + } else { + discussions, err = lab.IssueListDiscussions(rn, idNum) + } + if err != nil { + log.Fatal(err) + } + for _, discussion := range discussions { + for _, note := range discussion.Notes { + + if note.System { + if note.ID == reply { + fmt.Println("ERROR: Cannot reply to note", note.ID) + } + continue + } + + if note.ID != reply { + continue + } + + body := "" + if len(msgs) != 0 { + body, err = noteMsg(msgs, isMR, note.Body) + if err != nil { + _, f, l, _ := runtime.Caller(0) + log.Fatal(f+":"+strconv.Itoa(l)+" ", err) + } + } else if filename != "" { + content, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal(err) + } + body = string(content) + } else { + noteBody := "" + if quote { + noteBody = note.Body + noteBody = strings.Replace(noteBody, "\n", "\n>", -1) + if !update { + noteBody = ">" + noteBody + "\n" + } + } + body, err = noteMsg([]string{}, isMR, noteBody) + if err != nil { + _, f, l, _ := runtime.Caller(0) + log.Fatal(f+":"+strconv.Itoa(l)+" ", err) + } + } + + if body == "" && !resolve { + log.Fatal("aborting note due to empty note msg") + } + + if linebreak { + body = textToMarkdown(body) + } + + if update { + if isMR { + NoteURL, err = lab.UpdateMRDiscussionNote(rn, idNum, discussion.ID, note.ID, body) + } else { + NoteURL, err = lab.UpdateIssueDiscussionNote(rn, idNum, discussion.ID, note.ID, body) + } + } else { + if isMR { + if body != "" { + NoteURL, err = lab.AddMRDiscussionNote(rn, idNum, discussion.ID, body) + } + if resolve { + NoteURL, err = lab.ResolveMRDiscussion(rn, idNum, discussion.ID, reply) + } + } else { + NoteURL, err = lab.AddIssueDiscussionNote(rn, idNum, discussion.ID, body) + } + } + if err != nil { + log.Fatal(err) + } + fmt.Println(NoteURL) + } + } +} diff --git a/cmd/note_common_test.go b/cmd/note_common_test.go new file mode 100644 index 00000000..c18dffad --- /dev/null +++ b/cmd/note_common_test.go @@ -0,0 +1,53 @@ +package cmd + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// NOTE: tests for other functions, like createNote, are part of the +// issue_note test suite. + +func Test_noteMsg(t *testing.T) { + tests := []struct { + Name string + Msgs []string + ExpectedBody string + }{ + { + Name: "Using messages", + Msgs: []string{"note paragraph 1", "note paragraph 2"}, + ExpectedBody: "note paragraph 1\n\nnote paragraph 2", + }, + { + Name: "From Editor", + Msgs: nil, + ExpectedBody: "", // this is not a great test + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + test := test + t.Parallel() + body, err := noteMsg(test.Msgs, false, "\n") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.ExpectedBody, body) + }) + } +} + +func Test_noteText(t *testing.T) { + t.Parallel() + text, err := noteText("\n") + if err != nil { + t.Fatal(err) + } + require.Equal(t, ` + +# Write a message for this note. Commented lines are discarded.`, text) + +}