From 96cadaf4df5a59f7d89794fa8260934e56d59731 Mon Sep 17 00:00:00 2001 From: Olivier Tremblay Date: Wed, 20 Jun 2018 13:53:05 -0400 Subject: [PATCH] Implement attach command --- cmd/jkl/attach.go | 33 +++++++++++++++++++++++++++++++++ cmd/jkl/jkl.go | 4 +++- jiraclient.go | 12 ++++++------ jkl.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 cmd/jkl/attach.go diff --git a/cmd/jkl/attach.go b/cmd/jkl/attach.go new file mode 100644 index 0000000..c62f0a1 --- /dev/null +++ b/cmd/jkl/attach.go @@ -0,0 +1,33 @@ +package main + +import ( + "flag" + + "otremblay.com/jkl" +) + +type AttachCmd struct { + args []string + file string + taskKey string +} + +func NewAttachCmd(args []string) (*AttachCmd, error) { + ccmd := &AttachCmd{} + f := flag.NewFlagSet("x", flag.ExitOnError) + f.Parse(args) + if len(f.Args()) < 2 { + return nil, ErrNotEnoughArgs + } + ccmd.taskKey = f.Arg(0) + ccmd.file = f.Arg(1) + return ccmd, nil +} + +func (ecmd *AttachCmd) Attach() error { + return jkl.Attach(ecmd.taskKey, ecmd.file) +} + +func (ecmd *AttachCmd) Run() error { + return ecmd.Attach() +} diff --git a/cmd/jkl/jkl.go b/cmd/jkl/jkl.go index 3906575..68065bc 100644 --- a/cmd/jkl/jkl.go +++ b/cmd/jkl/jkl.go @@ -69,6 +69,8 @@ func getCmd(args []string, depth int) (Runner, error) { return NewFlagCmd(args[1:], false) case "link": return NewLinkCmd(args[1:]) + case "attach": + return NewAttachCmd(args[1:]) default: // Think about this real hard. // I want `jkl JIRA-1234 done` to move it to done. @@ -100,7 +102,7 @@ func getCmd(args []string, depth int) (Runner, error) { return nil, ErrTaskSubCommandNotFound } -var verbs = []string{"list", "create", "task", "edit", "comment", "edit-comment"} +var verbs = []string{"list", "create", "task", "edit", "comment", "edit-comment", "attach"} func init() { sort.Strings(verbs) diff --git a/jiraclient.go b/jiraclient.go index 8e15c1b..434dba8 100644 --- a/jiraclient.go +++ b/jiraclient.go @@ -93,16 +93,16 @@ func NewJiraClient(jiraRoot string) *JiraClient { } func (j *JiraClient) DoLess(req *http.Request) (*http.Response, error) { + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Accept", "application/json, text/plain, text/html") + return j.DoEvenLess(req) +} + +func (j *JiraClient) DoEvenLess(req *http.Request) (*http.Response, error) { var err error if os.Getenv("JIRA_COOKIEFILE") == "" { req.SetBasicAuth(os.Getenv("JIRA_USER"), os.Getenv("JIRA_PASSWORD")) } - if *Verbose { - fmt.Println("Jira User: ", os.Getenv("JIRA_USER")) - fmt.Println("Jira Password: ", os.Getenv("JIRA_PASSWORD")) - } - req.Header.Add("Content-Type", "application/json") - req.Header.Add("Accept", "application/json, text/plain, text/html") resp, err := j.Client.Do(req) if err != nil { return nil, err diff --git a/jkl.go b/jkl.go index 0da28a5..2e85cc1 100644 --- a/jkl.go +++ b/jkl.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "log" + "mime/multipart" "net/http" "net/url" "os" @@ -322,6 +323,50 @@ func LinkIssue(params []string) error { return nil } +func Attach(issueKey string, filename string) error { + bootHttpClient() + + // Prepare a form that you will submit to that URL. + var b bytes.Buffer + w := multipart.NewWriter(&b) + // Add your image file + f, err := os.Open(filename) + if err != nil { + return err + } + fi, err := os.Lstat(filename) + fw, err := w.CreateFormFile("file", fi.Name()) + if err != nil { + return err + } + if _, err = io.Copy(fw, f); err != nil { + return err + } + // Don't forget to close the multipart writer. + // If you don't close it, your request will be missing the terminating boundary. + w.Close() + + req, err := http.NewRequest("POST", "", &b) + + if err != nil { + return err + } + req.URL, err = url.Parse(httpClient.jiraRoot + "rest/" + fmt.Sprintf("api/2/issue/%s/attachments", issueKey)) + if err != nil { + return err + } + req.Header.Add("X-Atlassian-Token", "no-check") + req.Header.Add("Content-Type", w.FormDataContentType()) + res, err := httpClient.DoEvenLess(req) + + if err != nil { + s, _ := ioutil.ReadAll(res.Body) + fmt.Println(string(s)) + return err + } + return nil +} + func formatPayload(issue *JiraIssue) (io.Reader, error) { if issue.Fields != nil && issue.Fields.Project != nil &&