mirror of
https://github.com/Threnklyn/jira.git
synced 2026-05-19 04:33:28 +02:00
adding commands:
* create * dups * blocks * watch
This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -183,3 +185,94 @@ func (c *Cli) getTemplate(path string, dflt string) string {
|
|||||||
return readFile(file)
|
return readFile(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData map[string]interface{}, templateProcessor func(string) error) error {
|
||||||
|
|
||||||
|
tmpdir := fmt.Sprintf("%s/.jira.d/tmp", os.Getenv("HOME"))
|
||||||
|
fh, err := ioutil.TempFile(tmpdir, tmpFilePrefix); if err != nil {
|
||||||
|
log.Error("Failed to make temp file in %s: %s", tmpdir, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
tmpFileName := fmt.Sprintf("%s.yml", fh.Name())
|
||||||
|
if err := os.Rename(fh.Name(), tmpFileName); err != nil {
|
||||||
|
log.Error("Failed to rename %s to %s: %s", fh.Name(), fmt.Sprintf("%s.yml", fh.Name()), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = runTemplate(template, templateData, fh); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fh.Close()
|
||||||
|
|
||||||
|
editor, ok := c.opts["editor"]; if !ok {
|
||||||
|
editor = os.Getenv("JIRA_EDITOR"); if editor == "" {
|
||||||
|
editor = os.Getenv("EDITOR"); if editor == "" {
|
||||||
|
editor = "vim"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; true ; {
|
||||||
|
log.Debug("Running: %s %s", editor, tmpFileName)
|
||||||
|
cmd := exec.Command(editor, tmpFileName)
|
||||||
|
cmd.Stdout, cmd.Stderr, cmd.Stdin = os.Stdout, os.Stderr, os.Stdin
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Error("Failed to edit template with %s: %s", editor, err)
|
||||||
|
if promptYN("edit again?", true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
edited := make(map[string]interface{})
|
||||||
|
if fh, err := ioutil.ReadFile(tmpFileName); err != nil {
|
||||||
|
log.Error("Failed to read tmpfile %s: %s", tmpFileName, err)
|
||||||
|
if promptYN("edit again?", true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if err := yaml.Unmarshal(fh, &edited); err != nil {
|
||||||
|
log.Error("Failed to parse YAML: %s", err)
|
||||||
|
if promptYN("edit again?", true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fixed, err := yamlFixup(edited); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
edited = fixed.(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
mf := templateData["meta"].(map[string]interface{})["fields"]
|
||||||
|
f := edited["fields"].(map[string]interface{})
|
||||||
|
for k, _ := range f {
|
||||||
|
if _, ok := mf.(map[string]interface{})[k]; !ok {
|
||||||
|
err := fmt.Errorf("Field %s is not editable", k)
|
||||||
|
log.Error("%s", err)
|
||||||
|
if promptYN("edit again?", true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := jsonEncode(edited); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := templateProcessor(json); err != nil {
|
||||||
|
log.Error("%s", err)
|
||||||
|
if promptYN("edit again?", true) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+176
-95
@@ -4,11 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"fmt"
|
"fmt"
|
||||||
"code.google.com/p/gopass"
|
"code.google.com/p/gopass"
|
||||||
"os"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"os/exec"
|
"strings"
|
||||||
"io/ioutil"
|
|
||||||
"gopkg.in/yaml.v1"
|
|
||||||
// "github.com/kr/pretty"
|
// "github.com/kr/pretty"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,102 +104,30 @@ func (c *Cli) CmdEdit(issue string) error {
|
|||||||
issueData = data.(map[string]interface{})
|
issueData = data.(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
issueData["meta"] = editmeta.(map[string]interface{})["fields"]
|
issueData["meta"] = editmeta.(map[string]interface{})
|
||||||
|
issueData["overrides"] = c.opts
|
||||||
|
|
||||||
tmpdir := fmt.Sprintf("%s/.jira.d/tmp", os.Getenv("HOME"))
|
return c.editTemplate(
|
||||||
fh, err := ioutil.TempFile(tmpdir, fmt.Sprintf("%s-edit-", issue)); if err != nil {
|
c.getTemplate(".jira.d/templates/edit", default_edit_template),
|
||||||
log.Error("Failed to make temp file in %s: %s", tmpdir, err)
|
fmt.Sprintf("%s-edit-", issue),
|
||||||
return err
|
issueData,
|
||||||
}
|
func(json string) error {
|
||||||
defer fh.Close()
|
resp, err := c.put(uri, json); if err != nil {
|
||||||
|
|
||||||
tmpFileName := fmt.Sprintf("%s.yml", fh.Name())
|
|
||||||
if err := os.Rename(fh.Name(), tmpFileName); err != nil {
|
|
||||||
log.Error("Failed to rename %s to %s: %s", fh.Name(), fmt.Sprintf("%s.yml", fh.Name()), err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = runTemplate(c.getTemplate(".jira.d/templates/edit", default_edit_template), issueData, fh); if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fh.Close()
|
|
||||||
|
|
||||||
editor, ok := c.opts["editor"]; if !ok {
|
|
||||||
editor = os.Getenv("JIRA_EDITOR"); if editor == "" {
|
|
||||||
editor = os.Getenv("EDITOR"); if editor == "" {
|
|
||||||
editor = "vim"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ; true ; {
|
|
||||||
log.Debug("Running: %s %s", editor, tmpFileName)
|
|
||||||
cmd := exec.Command(editor, tmpFileName)
|
|
||||||
cmd.Stdout, cmd.Stderr, cmd.Stdin = os.Stdout, os.Stderr, os.Stdin
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
log.Error("Failed to edit template with %s: %s", editor, err)
|
|
||||||
if promptYN("edit again?", true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
edited := make(map[string]interface{})
|
|
||||||
if fh, err := ioutil.ReadFile(tmpFileName); err != nil {
|
|
||||||
log.Error("Failed to read tmpfile %s: %s", tmpFileName, err)
|
|
||||||
if promptYN("edit again?", true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
if err := yaml.Unmarshal(fh, &edited); err != nil {
|
|
||||||
log.Error("Failed to parse YAML: %s", err)
|
|
||||||
if promptYN("edit again?", true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
if fixed, err := yamlFixup(edited); err != nil {
|
fmt.Printf("OK %s %s/browse/%s\n", issueData["key"], c.endpoint, issueData["key"])
|
||||||
return err
|
return nil
|
||||||
} else {
|
} else {
|
||||||
edited = fixed.(map[string]interface{})
|
logBuffer := bytes.NewBuffer(make([]byte,0))
|
||||||
}
|
resp.Write(logBuffer)
|
||||||
|
err := fmt.Errorf("Unexpected Response From PUT")
|
||||||
mf := editmeta.(map[string]interface{})["fields"]
|
log.Error("%s:\n%s", err, logBuffer)
|
||||||
f := edited["fields"].(map[string]interface{})
|
|
||||||
for k, _ := range f {
|
|
||||||
if _, ok := mf.(map[string]interface{})[k]; !ok {
|
|
||||||
err := fmt.Errorf("Field %s is not editable", k)
|
|
||||||
log.Error("%s", err)
|
|
||||||
if promptYN("edit again?", true) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
)
|
||||||
json, err := jsonEncode(edited); if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.put(uri, json); if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode == 204 {
|
|
||||||
fmt.Printf("OK %s %s", issueData["key"], issueData["self"])
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
logBuffer := bytes.NewBuffer(make([]byte,0))
|
|
||||||
resp.Write(logBuffer)
|
|
||||||
err := fmt.Errorf("Unexpected Response From PUT")
|
|
||||||
log.Error("%s:\n%s", err, logBuffer)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cli) CmdEditMeta(issue string) error {
|
func (c *Cli) CmdEditMeta(issue string) error {
|
||||||
@@ -232,6 +157,12 @@ func (c *Cli) CmdCreateMeta(project string, issuetype string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if val, ok := data.(map[string]interface{})["projects"]; ok {
|
||||||
|
if val, ok = val.([]interface{})[0].(map[string]interface{})["issuetypes"]; ok {
|
||||||
|
data = val.([]interface{})[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return runTemplate(c.getTemplate(".jira.d/templates/createmeta", default_fields_template), data, nil)
|
return runTemplate(c.getTemplate(".jira.d/templates/createmeta", default_fields_template), data, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,3 +174,153 @@ func (c *Cli) CmdTransitions(issue string) error {
|
|||||||
}
|
}
|
||||||
return runTemplate(c.getTemplate(".jira.d/templates/transitions", default_transitions_template), data, nil)
|
return runTemplate(c.getTemplate(".jira.d/templates/transitions", default_transitions_template), data, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cli) CmdCreate(project string, issuetype string) error {
|
||||||
|
log.Debug("create called")
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&issuetypeNames=%s&expand=projects.issuetypes.fields", c.endpoint, project, issuetype)
|
||||||
|
data, err := responseToJson(c.get(uri)); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
issueData := make(map[string]interface{})
|
||||||
|
issueData["overrides"] = c.opts
|
||||||
|
|
||||||
|
if val, ok := data.(map[string]interface{})["projects"]; ok {
|
||||||
|
if val, ok = val.([]interface{})[0].(map[string]interface{})["issuetypes"]; ok {
|
||||||
|
issueData["meta"] = val.([]interface{})[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitizedType := strings.ToLower(strings.Replace(issuetype, " ", "", -1))
|
||||||
|
return c.editTemplate(
|
||||||
|
c.getTemplate(fmt.Sprintf(".jira.d/templates/create-%s", sanitizedType), default_create_template),
|
||||||
|
fmt.Sprintf("create-%s-", sanitizedType),
|
||||||
|
issueData,
|
||||||
|
func(json string) error {
|
||||||
|
log.Debug("JSON: %s", json)
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issue", c.endpoint)
|
||||||
|
resp, err := c.post(uri, json); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == 201 {
|
||||||
|
// response: {"id":"410836","key":"PROJ-238","self":"https://jira/rest/api/2/issue/410836"}
|
||||||
|
if json, err := responseToJson(resp, nil); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
key := json.(map[string]interface{})["key"]
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", key, c.endpoint, key)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
logBuffer := bytes.NewBuffer(make([]byte,0))
|
||||||
|
resp.Write(logBuffer)
|
||||||
|
err := fmt.Errorf("Unexpected Response From PUT")
|
||||||
|
log.Error("%s:\n%s", err, logBuffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) CmdIssueLinkTypes() error {
|
||||||
|
log.Debug("Transitions called")
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issueLinkType", c.endpoint)
|
||||||
|
data, err := responseToJson(c.get(uri)); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return runTemplate(c.getTemplate(".jira.d/templates/issuelinktypes", default_fields_template), data, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) CmdBlocks(blocker string, issue string) error {
|
||||||
|
log.Debug("blocks called")
|
||||||
|
|
||||||
|
json, err := jsonEncode(map[string]interface{}{
|
||||||
|
"type": map[string]string{
|
||||||
|
"name": "Depends",
|
||||||
|
},
|
||||||
|
"inwardIssue": map[string]string{
|
||||||
|
"key": issue,
|
||||||
|
},
|
||||||
|
"outwardIssue": map[string]string{
|
||||||
|
"key": blocker,
|
||||||
|
},
|
||||||
|
}); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issueLink", c.endpoint)
|
||||||
|
resp, err := c.post(uri, json); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode == 201 {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||||
|
} else {
|
||||||
|
logBuffer := bytes.NewBuffer(make([]byte,0))
|
||||||
|
resp.Write(logBuffer)
|
||||||
|
err := fmt.Errorf("Unexpected Response From PUT")
|
||||||
|
log.Error("%s:\n%s", err, logBuffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) CmdDups(duplicate string, issue string) error {
|
||||||
|
log.Debug("dups called")
|
||||||
|
|
||||||
|
json, err := jsonEncode(map[string]interface{}{
|
||||||
|
"type": map[string]string{
|
||||||
|
"name": "Duplicate",
|
||||||
|
},
|
||||||
|
"inwardIssue": map[string]string{
|
||||||
|
"key": duplicate,
|
||||||
|
},
|
||||||
|
"outwardIssue": map[string]string{
|
||||||
|
"key": issue,
|
||||||
|
},
|
||||||
|
}); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issueLink", c.endpoint)
|
||||||
|
resp, err := c.post(uri, json); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode == 201 {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||||
|
} else {
|
||||||
|
logBuffer := bytes.NewBuffer(make([]byte,0))
|
||||||
|
resp.Write(logBuffer)
|
||||||
|
err := fmt.Errorf("Unexpected Response From PUT")
|
||||||
|
log.Error("%s:\n%s", err, logBuffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (c *Cli) CmdWatch(issue string, watcher string) error {
|
||||||
|
log.Debug("dups called")
|
||||||
|
|
||||||
|
json, err := jsonEncode(watcher); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/watchers", c.endpoint, issue)
|
||||||
|
resp, err := c.post(uri, json); if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||||
|
} else {
|
||||||
|
logBuffer := bytes.NewBuffer(make([]byte,0))
|
||||||
|
resp.Write(logBuffer)
|
||||||
|
err := fmt.Errorf("Unexpected Response From PUT")
|
||||||
|
log.Error("%s:\n%s", err, logBuffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-4
@@ -31,22 +31,43 @@ const default_edit_template = `update:
|
|||||||
|
|
||||||
fields:
|
fields:
|
||||||
summary: {{ .fields.summary }}
|
summary: {{ .fields.summary }}
|
||||||
components: # {{ range .meta.components.allowedValues }}{{.name}}, {{end}}{{ range .fields.components }}
|
components: # {{ range .meta.fields.components.allowedValues }}{{.name}}, {{end}}{{ range .fields.components }}
|
||||||
- name: {{ .name }}{{end}}
|
- name: {{ .name }}{{end}}
|
||||||
assignee:
|
assignee:
|
||||||
name: {{ .fields.assignee.name }}
|
name: {{ if .fields.assignee }}{{ .fields.assignee.name }}{{end}}
|
||||||
reporter:
|
reporter:
|
||||||
name: {{ .fields.reporter.name }}
|
name: {{ .fields.reporter.name }}
|
||||||
# watchers
|
# watchers
|
||||||
customfield_10110: {{ range .fields.customfield_10110 }}
|
customfield_10110: {{ range .fields.customfield_10110 }}
|
||||||
- name: {{ .name }}{{end}}
|
- name: {{ .name }}{{end}}
|
||||||
priority: # {{ range .meta.priority.allowedValues }}{{.name}}, {{end}}
|
priority: # {{ range .meta.fields.priority.allowedValues }}{{.name}}, {{end}}
|
||||||
name: {{ .fields.priority.name }}
|
name: {{ .fields.priority.name }}
|
||||||
description: |
|
description: |
|
||||||
{{ .fields.description | indent 4 }}
|
{{ or .fields.description "" | indent 4 }}
|
||||||
`
|
`
|
||||||
const default_transitions_template = `{{ range .transitions }}{{color "+bh"}}{{.name | printf "%-13s" }}{{color "reset"}} -> {{.to.name}}
|
const default_transitions_template = `{{ range .transitions }}{{color "+bh"}}{{.name | printf "%-13s" }}{{color "reset"}} -> {{.to.name}}
|
||||||
{{end}}`
|
{{end}}`
|
||||||
|
|
||||||
const default_issuetypes_template = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}}
|
const default_issuetypes_template = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}}
|
||||||
{{end}}{{end}}`
|
{{end}}{{end}}`
|
||||||
|
|
||||||
|
const default_create_template = `fields:
|
||||||
|
project:
|
||||||
|
key: {{ .overrides.project }}
|
||||||
|
issuetype:
|
||||||
|
name: {{ .overrides.issuetype }}
|
||||||
|
summary: {{ or .overrides.summary "" }}
|
||||||
|
priority: # {{ range .meta.fields.priority.allowedValues }}{{.name}}, {{end}}
|
||||||
|
name: {{ or .overrides.priority "" }}
|
||||||
|
components: # {{ range .meta.fields.components.allowedValues }}{{.name}}, {{end}}{{ range split "," (or .overrides.components "")}}
|
||||||
|
- name: {{ . }}{{end}}
|
||||||
|
description: |
|
||||||
|
{{ or .overrides.description "" | indent 4 }}
|
||||||
|
assignee:
|
||||||
|
name: {{ or .overrides.assignee .overrides.user}}
|
||||||
|
reporter:
|
||||||
|
name: {{ or .overrides.reporter .overrides.user }}
|
||||||
|
# watchers
|
||||||
|
customfield_10110:
|
||||||
|
- name:
|
||||||
|
`
|
||||||
|
|||||||
+8
-1
@@ -94,6 +94,9 @@ func runTemplate(templateContent string, data interface{}, out io.Writer) error
|
|||||||
"color": func(color string) string {
|
"color": func(color string) string {
|
||||||
return ansi.ColorCode(color)
|
return ansi.ColorCode(color)
|
||||||
},
|
},
|
||||||
|
"split": func(sep string, content string) []string {
|
||||||
|
return strings.Split(content, sep)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if tmpl, err := template.New("template").Funcs(funcs).Parse(templateContent); err != nil {
|
if tmpl, err := template.New("template").Funcs(funcs).Parse(templateContent); err != nil {
|
||||||
log.Error("Failed to parse template: %s", err)
|
log.Error("Failed to parse template: %s", err)
|
||||||
@@ -157,7 +160,10 @@ func promptYN(prompt string, yes bool) bool {
|
|||||||
|
|
||||||
fmt.Printf("%s", prompt)
|
fmt.Printf("%s", prompt)
|
||||||
text, _ := reader.ReadString('\n')
|
text, _ := reader.ReadString('\n')
|
||||||
ans := strings.ToLower(text)
|
ans := strings.ToLower(strings.TrimRight(text, "\n"))
|
||||||
|
if ans == "" {
|
||||||
|
return yes
|
||||||
|
}
|
||||||
if( strings.HasPrefix(ans, "y") ) {
|
if( strings.HasPrefix(ans, "y") ) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -205,3 +211,4 @@ func yamlFixup( data interface{} ) (interface{}, error) {
|
|||||||
default: return d, nil
|
default: return d, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+72
-11
@@ -22,16 +22,18 @@ Usage:
|
|||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] login
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] login
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] ls [-q JQL]
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] ls [-q JQL]
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] view ISSUE
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] view ISSUE
|
||||||
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] issuelinktypes
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] ISSUE
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] ISSUE
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] editmeta ISSUE
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] editmeta ISSUE
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] edit ISSUE
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] edit ISSUE [-o KEY=VAL]...
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] issuetypes [-p PROJECT]
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] issuetypes [-p PROJECT]
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] createmeta [-p PROJECT] [-i ISSUETYPE]
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] createmeta [-p PROJECT] [-i ISSUETYPE]
|
||||||
jira [-v ...] [-u USER] [-e URI] [-t FILE] transitions ISSUE
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] transitions ISSUE
|
||||||
|
jira [-v ...] [-u USER] [-e URI] [-t FILE] create [-p PROJECT] [-i ISSUETYPE] [-o KEY=VAL]...
|
||||||
|
jira [-v ...] [-u USER] [-e URI] DUPLICATE dups ISSUE
|
||||||
|
jira [-v ...] [-u USER] [-e URI] BLOCKER blocks ISSUE
|
||||||
|
jira [-v ...] [-u USER] [-e URI] watch ISSUE [WATCHER]
|
||||||
|
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] [-t FILE] create [-p PROJECT] [-i ISSUETYPE]
|
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] DUPLICATE dups ISSUE
|
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] BLOCKER blocks ISSUE
|
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] close ISSUE [-m COMMENT]
|
jira TODO [-v ...] [-u USER] [-e URI] close ISSUE [-m COMMENT]
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] resolve ISSUE [-m COMMENT]
|
jira TODO [-v ...] [-u USER] [-e URI] resolve ISSUE [-m COMMENT]
|
||||||
jira TODO [-v ...] [-u USER] [-e URI] comment ISSUE [-m COMMENT]
|
jira TODO [-v ...] [-u USER] [-e URI] comment ISSUE [-m COMMENT]
|
||||||
@@ -52,6 +54,7 @@ List Options:
|
|||||||
Create Options:
|
Create Options:
|
||||||
-p --project=PROJECT Jira Project Name
|
-p --project=PROJECT Jira Project Name
|
||||||
-i --issuetype=ISSUETYPE Jira Issue Type (default: Bug)
|
-i --issuetype=ISSUETYPE Jira Issue Type (default: Bug)
|
||||||
|
-o --override=KEY:VAL Set custom key/value pairs
|
||||||
`, user)
|
`, user)
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "0.0.1", false, false)
|
args, _ := docopt.Parse(usage, nil, true, "0.0.1", false, false)
|
||||||
@@ -73,7 +76,6 @@ Create Options:
|
|||||||
|
|
||||||
log.Info("Args: %v", args)
|
log.Info("Args: %v", args)
|
||||||
|
|
||||||
|
|
||||||
opts := make(map[string]string)
|
opts := make(map[string]string)
|
||||||
loadConfigs(opts)
|
loadConfigs(opts)
|
||||||
|
|
||||||
@@ -82,12 +84,23 @@ Create Options:
|
|||||||
for key,val := range args {
|
for key,val := range args {
|
||||||
if val != nil && strings.HasPrefix(key, "--") {
|
if val != nil && strings.HasPrefix(key, "--") {
|
||||||
opt := key[2:]
|
opt := key[2:]
|
||||||
switch v := val.(type) {
|
if opt == "override" {
|
||||||
// only deal with string opts, ignore
|
for _, v := range val.([]string) {
|
||||||
// other types, like int (for now) since
|
if strings.Contains(v, "=") {
|
||||||
// they are only used for --verbose
|
kv := strings.SplitN(v, "=", 2)
|
||||||
case string:
|
opts[kv[0]] = kv[1]
|
||||||
opts[opt] = v
|
} else {
|
||||||
|
log.Error("Malformed override, expected KEY=VALUE, got %s", v)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch v := val.(type) {
|
||||||
|
case string:
|
||||||
|
opts[opt] = v
|
||||||
|
case int:
|
||||||
|
opts[opt] = fmt.Sprintf("%d", v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,6 +135,8 @@ Create Options:
|
|||||||
} else if val, ok := args["editmeta"]; ok && val.(bool) {
|
} else if val, ok := args["editmeta"]; ok && val.(bool) {
|
||||||
issue, _ := args["ISSUE"]
|
issue, _ := args["ISSUE"]
|
||||||
err = c.CmdEditMeta(issue.(string))
|
err = c.CmdEditMeta(issue.(string))
|
||||||
|
} else if val, ok := args["issuelinktypes"]; ok && val.(bool) {
|
||||||
|
err = c.CmdIssueLinkTypes()
|
||||||
} else if val, ok := args["issuetypes"]; ok && val.(bool) {
|
} else if val, ok := args["issuetypes"]; ok && val.(bool) {
|
||||||
var project interface{}
|
var project interface{}
|
||||||
if project, ok = opts["project"]; !ok {
|
if project, ok = opts["project"]; !ok {
|
||||||
@@ -140,9 +155,55 @@ Create Options:
|
|||||||
issuetype = "Bug"
|
issuetype = "Bug"
|
||||||
}
|
}
|
||||||
err = c.CmdCreateMeta(project.(string), issuetype.(string))
|
err = c.CmdCreateMeta(project.(string), issuetype.(string))
|
||||||
|
} else if val, ok := args["create"]; ok && val.(bool) {
|
||||||
|
var project interface{}
|
||||||
|
if project, ok = opts["project"]; !ok {
|
||||||
|
log.Error("missing PROJECT argument or \"project\" property in the config file")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
var issuetype interface{}
|
||||||
|
if issuetype, ok = opts["issuetype"]; !ok {
|
||||||
|
issuetype = "Bug"
|
||||||
|
}
|
||||||
|
err = c.CmdCreate(project.(string), issuetype.(string))
|
||||||
} else if val, ok := args["transitions"]; ok && val.(bool) {
|
} else if val, ok := args["transitions"]; ok && val.(bool) {
|
||||||
issue, _ := args["ISSUE"]
|
issue, _ := args["ISSUE"]
|
||||||
err = c.CmdTransitions(issue.(string))
|
err = c.CmdTransitions(issue.(string))
|
||||||
|
} else if val, ok := args["blocks"]; ok && val.(bool) {
|
||||||
|
if blocker, ok := args["BLOCKER"].(string); ok {
|
||||||
|
if issue, ok := args["ISSUE"].(string); ok {
|
||||||
|
err = c.CmdBlocks(blocker, issue)
|
||||||
|
} else {
|
||||||
|
log.Error("missing ISSUE")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Error("missing BLOCKER")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else if val, ok := args["dups"]; ok && val.(bool) {
|
||||||
|
if duplicate, ok := args["DUPLICATE"].(string); ok {
|
||||||
|
if issue, ok := args["ISSUE"].(string); ok {
|
||||||
|
err = c.CmdDups(duplicate, issue)
|
||||||
|
} else {
|
||||||
|
log.Error("missing ISSUE")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Error("missing BLOCKER")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else if val, ok := args["watch"]; ok && val.(bool) {
|
||||||
|
if issue, ok := args["ISSUE"].(string); ok {
|
||||||
|
var watcher string
|
||||||
|
if watcher, ok = args["WATCHER"].(string); !ok {
|
||||||
|
watcher = user
|
||||||
|
}
|
||||||
|
err = c.CmdWatch(issue, watcher)
|
||||||
|
} else {
|
||||||
|
log.Error("missing ISSUE")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
} else if val, ok := args["ISSUE"]; ok {
|
} else if val, ok := args["ISSUE"]; ok {
|
||||||
err = c.CmdView(val.(string))
|
err = c.CmdView(val.(string))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user