Implement attach command
This commit is contained in:
parent
22a1ba56e5
commit
96cadaf4df
4 changed files with 87 additions and 7 deletions
33
cmd/jkl/attach.go
Normal file
33
cmd/jkl/attach.go
Normal file
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,8 @@ func getCmd(args []string, depth int) (Runner, error) {
|
||||||
return NewFlagCmd(args[1:], false)
|
return NewFlagCmd(args[1:], false)
|
||||||
case "link":
|
case "link":
|
||||||
return NewLinkCmd(args[1:])
|
return NewLinkCmd(args[1:])
|
||||||
|
case "attach":
|
||||||
|
return NewAttachCmd(args[1:])
|
||||||
default:
|
default:
|
||||||
// Think about this real hard.
|
// Think about this real hard.
|
||||||
// I want `jkl JIRA-1234 done` to move it to done.
|
// 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
|
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() {
|
func init() {
|
||||||
sort.Strings(verbs)
|
sort.Strings(verbs)
|
||||||
|
|
|
||||||
|
|
@ -93,16 +93,16 @@ func NewJiraClient(jiraRoot string) *JiraClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JiraClient) DoLess(req *http.Request) (*http.Response, error) {
|
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
|
var err error
|
||||||
if os.Getenv("JIRA_COOKIEFILE") == "" {
|
if os.Getenv("JIRA_COOKIEFILE") == "" {
|
||||||
req.SetBasicAuth(os.Getenv("JIRA_USER"), os.Getenv("JIRA_PASSWORD"))
|
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)
|
resp, err := j.Client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
45
jkl.go
45
jkl.go
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -322,6 +323,50 @@ func LinkIssue(params []string) error {
|
||||||
return nil
|
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) {
|
func formatPayload(issue *JiraIssue) (io.Reader, error) {
|
||||||
if issue.Fields != nil &&
|
if issue.Fields != nil &&
|
||||||
issue.Fields.Project != nil &&
|
issue.Fields.Project != nil &&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue