From 7bbd57107850a2c320e239094e3ad615443d6457 Mon Sep 17 00:00:00 2001 From: Cory Bennett Date: Sun, 13 Sep 2015 01:21:45 -0700 Subject: [PATCH] use optigo for option parsing, drop docopt --- jira/cli/cli.go | 16 +- jira/cli/commands.go | 22 +- jira/main.go | 480 ++++++++++++++++++++----------------------- 3 files changed, 249 insertions(+), 269 deletions(-) diff --git a/jira/cli/cli.go b/jira/cli/cli.go index 83b682eb..305bd262 100644 --- a/jira/cli/cli.go +++ b/jira/cli/cli.go @@ -22,18 +22,18 @@ var log = logging.MustGetLogger("jira.cli") type Cli struct { endpoint *url.URL - opts map[string]string + opts map[string]interface{} cookieFile string ua *http.Client } -func New(opts map[string]string) *Cli { +func New(opts map[string]interface{}) *Cli { homedir := os.Getenv("HOME") cookieJar, _ := cookiejar.New(nil) - endpoint, _ := opts["endpoint"] + endpoint, _ := opts["endpoint"].(string) url, _ := url.Parse(strings.TrimRight(endpoint, "/")) - if project, ok := opts["project"]; ok { + if project, ok := opts["project"].(string); ok { opts["project"] = strings.ToUpper(project) } @@ -175,7 +175,7 @@ func (c *Cli) makeRequest(req *http.Request) (resp *http.Response, err error) { } func (c *Cli) getTemplate(name string) string { - if override, ok := c.opts["template"]; ok { + if override, ok := c.opts["template"].(string); ok { if _, err := os.Stat(override); err == nil { return readFile(override) } else { @@ -233,7 +233,7 @@ func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData m fh.Close() - editor, ok := c.opts["editor"] + editor, ok := c.opts["editor"].(string) if !ok { editor = os.Getenv("JIRA_EDITOR") if editor == "" { @@ -245,7 +245,7 @@ func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData m } editing := true - if val, ok := c.opts["edit"]; ok && val == "false" { + if val, ok := c.opts["edit"].(bool); ok && !val { editing = false } @@ -340,7 +340,7 @@ func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData m } func (c *Cli) Browse(issue string) error { - if val, ok := c.opts["browse"]; ok && val == "true" { + if val, ok := c.opts["browse"].(bool); ok && val { if runtime.GOOS == "darwin" { return exec.Command("open", fmt.Sprintf("%s/browse/%s", c.endpoint, issue)).Run() } else if runtime.GOOS == "linux" { diff --git a/jira/cli/commands.go b/jira/cli/commands.go index 5f00e70f..04397286 100644 --- a/jira/cli/commands.go +++ b/jira/cli/commands.go @@ -14,7 +14,7 @@ func (c *Cli) CmdLogin() error { uri := fmt.Sprintf("%s/rest/auth/1/session", c.endpoint) for true { req, _ := http.NewRequest("GET", uri, nil) - user, _ := c.opts["user"] + user, _ := c.opts["user"].(string) prompt := fmt.Sprintf("Enter Password for %s: ", user) passwd, _ := gopass.GetPass(prompt) @@ -69,7 +69,7 @@ func (c *Cli) CmdList() error { var query string var ok bool // project = BAKERY and status not in (Resolved, Closed) - if query, ok = c.opts["query"]; !ok { + if query, ok = c.opts["query"].(string); !ok { qbuff := bytes.NewBufferString("resolution = unresolved") if project, ok := c.opts["project"]; !ok { err := fmt.Errorf("Missing required arguments, either 'query' or 'project' are required") @@ -107,7 +107,7 @@ func (c *Cli) CmdList() error { } fields := make([]string, 0) - if qf, ok := c.opts["queryfields"]; ok { + if qf, ok := c.opts["queryfields"].(string); ok { fields = strings.Split(qf, ",") } else { fields = append(fields, "summary") @@ -213,7 +213,8 @@ func (c *Cli) CmdTransitionMeta(issue string) error { return runTemplate(c.getTemplate("transmeta"), data, nil) } -func (c *Cli) CmdIssueTypes(project string) error { +func (c *Cli) CmdIssueTypes() error { + project := c.opts["project"].(string) log.Debug("issueTypes called") uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s", c.endpoint, project) data, err := responseToJson(c.get(uri)) @@ -224,7 +225,9 @@ func (c *Cli) CmdIssueTypes(project string) error { return runTemplate(c.getTemplate("issuetypes"), data, nil) } -func (c *Cli) CmdCreateMeta(project string, issuetype string) error { +func (c *Cli) CmdCreateMeta() error { + project := c.opts["project"].(string) + issuetype := c.opts["issuetype"].(string) log.Debug("createMeta 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)) @@ -257,7 +260,9 @@ func (c *Cli) CmdTransitions(issue string) error { return runTemplate(c.getTemplate("transitions"), data, nil) } -func (c *Cli) CmdCreate(project string, issuetype string) error { +func (c *Cli) CmdCreate() error { + project := c.opts["project"].(string) + issuetype := c.opts["issuetype"].(string) 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) @@ -399,7 +404,8 @@ func (c *Cli) CmdDups(duplicate string, issue string) error { return nil } -func (c *Cli) CmdWatch(issue string, watcher string) error { +func (c *Cli) CmdWatch(issue string) error { + watcher := c.opts["watcher"].(string) log.Debug("watch called") json, err := jsonEncode(watcher) @@ -568,7 +574,7 @@ func (c *Cli) CmdAssign(issue string, user string) error { } func (c *Cli) CmdExportTemplates() error { - dir := c.opts["directory"] + dir := c.opts["directory"].(string) if err := mkdir(dir); err != nil { return err } diff --git a/jira/main.go b/jira/main.go index e85bde31..e0957d17 100644 --- a/jira/main.go +++ b/jira/main.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" "github.com/Netflix-Skunkworks/go-jira/jira/cli" - "github.com/docopt/docopt-go" + "github.com/coryb/optigo" "github.com/op/go-logging" "gopkg.in/yaml.v2" "io/ioutil" @@ -17,39 +17,63 @@ var log = logging.MustGetLogger("jira") var format = "%{color}%{time:2006-01-02T15:04:05.000Z07:00} %{level:-5s} [%{shortfile}]%{color:reset} %{message}" func main() { + logBackend := logging.NewLogBackend(os.Stderr, "", 0) + logging.SetBackend( + logging.NewBackendFormatter( + logBackend, + logging.MustStringFormatter(format), + ), + ) + logging.SetLevel(logging.NOTICE, "") + user := os.Getenv("USER") home := os.Getenv("HOME") - defaultMaxResults := "500" - usage := fmt.Sprintf(` + defaultMaxResults := 500 + + usage := func(ok bool) { + printer := fmt.Printf + if !ok { + printer = func(format string, args ...interface{}) (int, error) { + return fmt.Fprintf(os.Stderr, format, args...) + } + defer func() { + os.Exit(1) + }() + } else { + defer func() { + os.Exit(0) + }() + } + output := fmt.Sprintf(` Usage: - jira [-v ...] [-u USER] [-e URI] [-t FILE] (ls|list) ( [-q JQL] | [-p PROJECT] [-c COMPONENT] [-a ASSIGNEE] [-i ISSUETYPE] [-w WATCHER] [-r REPORTER]) [-f FIELDS] [-s ORDER] [--max_results MAX_RESULTS] - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] view ISSUE - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] edit ISSUE [--noedit] [-m COMMENT] [-o KEY=VAL]... - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] create [--noedit] [-p PROJECT] [-i ISSUETYPE] [-o KEY=VAL]... - jira [-v ...] [-u USER] [-e URI] [-b] DUPLICATE dups ISSUE - jira [-v ...] [-u USER] [-e URI] [-b] BLOCKER blocks ISSUE - jira [-v ...] [-u USER] [-e URI] [-b] watch ISSUE [-w WATCHER] - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] (trans|transition) TRANSITION ISSUE [-m COMMENT] [-o KEY=VAL] [--noedit] - jira [-v ...] [-u USER] [-e URI] [-b] ack ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] close ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] resolve ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] reopen ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] start ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] stop ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] comment ISSUE [-m COMMENT] - jira [-v ...] [-u USER] [-e URI] [-b] take ISSUE - jira [-v ...] [-u USER] [-e URI] [-b] (assign|give) ISSUE ASSIGNEE - jira [-v ...] [-u USER] [-e URI] [-t FILE] fields - jira [-v ...] [-u USER] [-e URI] [-t FILE] issuelinktypes - jira [-v ...] [-u USER] [-e URI] [-b][-t FILE] transmeta ISSUE - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] editmeta ISSUE - 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] [-b] [-t FILE] transitions ISSUE - jira [-v ...] export-templates [-d DIR] [-t template] - jira [-v ...] [-u USER] [-e URI] (b|browse) ISSUE - jira [-v ...] [-u USER] [-e URI] [-t FILE] login - jira [-v ...] [-u USER] [-e URI] [-b] [-t FILE] ISSUE + jira (ls|list) ( [-q JQL] | [-p PROJECT] [-c COMPONENT] [-a ASSIGNEE] [-i ISSUETYPE] [-w WATCHER] [-r REPORTER]) [-f FIELDS] [-s ORDER] [--max_results MAX_RESULTS] + jira view ISSUE + jira edit ISSUE [--noedit] [-m COMMENT] [-o KEY=VAL]... + jira create [--noedit] [-p PROJECT] [-i ISSUETYPE] [-o KEY=VAL]... + jira DUPLICATE dups ISSUE + jira BLOCKER blocks ISSUE + jira watch ISSUE [-w WATCHER] + jira (trans|transition) TRANSITION ISSUE [-m COMMENT] [-o KEY=VAL] [--noedit] + jira ack ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira close ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira resolve ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira reopen ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira start ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira stop ISSUE [-m COMMENT] [-o KEY=VAL] [--edit] + jira comment ISSUE [-m COMMENT] + jira take ISSUE + jira (assign|give) ISSUE ASSIGNEE + jira fields + jira issuelinktypes + jira transmeta ISSUE + jira editmeta ISSUE + jira issuetypes [-p PROJECT] + jira createmeta [-p PROJECT] [-i ISSUETYPE] + jira transitions ISSUE + jira export-templates [-d DIR] [-t template] + jira (b|browse) ISSUE + jira login + jira ISSUE General Options: -e --endpoint=URI URI to use for jira @@ -57,7 +81,6 @@ General Options: -t --template=FILE Template file to use for output/editing -u --user=USER Username to use for authenticaion (default: %s) -v --verbose Increase output logging - --version Show this version Command Options: -a --assignee=USER Username assigned the issue @@ -67,90 +90,118 @@ Command Options: -f --queryfields=FIELDS Fields that are used in "list" template: (default: summary,created,priority,status,reporter,assignee) -i --issuetype=ISSUETYPE Jira Issue Type (default: Bug) -m --comment=COMMENT Comment message for transition - -o --override=KEY:VAL Set custom key/value pairs + -o --override=KEY=VAL Set custom key/value pairs -p --project=PROJECT Project to Search for -q --query=JQL Jira Query Language expression for the search -r --reporter=USER Reporter to search for -s --sort=ORDER For list operations, sort issues (default: priority asc, created) -w --watcher=USER Watcher to add to issue (default: %s) or Watcher to search for - --max_results=VAL Maximum number of results to return in query (default: %s) + --max_results=VAL Maximum number of results to return in query (default: %d) `, user, fmt.Sprintf("%s/.jira.d/templates", home), user, defaultMaxResults) + printer(output) + } - args, err := docopt.Parse(usage, nil, true, "0.0.8", false, false) - if err != nil { - log.Error("Failed to parse options: %s", err) - os.Exit(1) + jiraCommands := map[string]string{ + "list": "list", + "ls": "list", + "view": "view", + "edit": "edit", + "create": "create", + "dups": "dups", + "blocks": "blocks", + "watch": "watch", + "trans": "transition", + "transition": "transition", + "ack": "acknowledge", + "acknowledge": "acknowledge", + "close": "close", + "resolve": "resolve", + "reopen": "reopen", + "start": "start", + "stop": "stop", + "comment": "comment", + "take": "take", + "assign": "assign", + "give": "assign", + "fields": "fields", + "issuelinktypes": "issuelinktypes", + "transmeta": "transmeta", + "editmeta": "editmeta", + "issuetypes": "issuetypes", + "createmeta": "createmeta", + "transitions": "transitions", + "export-templates": "export-templates", + "browse": "browse", + "login": "login", } - logBackend := logging.NewLogBackend(os.Stderr, "", 0) - logging.SetBackend( - logging.NewBackendFormatter( - logBackend, - logging.MustStringFormatter(format), - ), - ) - logging.SetLevel(logging.NOTICE, "") - if verbose, ok := args["--verbose"]; ok { - if verbose.(int) > 1 { - logging.SetLevel(logging.DEBUG, "") - } else if verbose.(int) > 0 { - logging.SetLevel(logging.INFO, "") - } + + opts := map[string]interface{}{ + "user": user, + "issuetype": "Bug", + "watcher": user, + "queryfields": "summary,created,priority,status,reporter,assignee", + "directory": fmt.Sprintf("%s/.jira.d/templates", home), + "sort": "priority asc, created", + "max_results": defaultMaxResults, } + overrides := make(map[string]string) - log.Info("Args: %v", args) + setopt := func(name string, value interface{}) { + opts[name] = value + } - populateEnv(args) + op := optigo.NewDirectAssignParser(map[string]interface{}{ + "h|help": usage, + "v|verbose+": func() { + logging.SetLevel(logging.GetLevel("")+1, "") + }, + "dryrun": setopt, + "b|browse": setopt, + "editor=s": setopt, + "u|user=s": setopt, + "endpoint=s": setopt, + "t|template=s": setopt, + "q|query=s": setopt, + "p|project=s": setopt, + "c|component=s": setopt, + "a|assignee=s": setopt, + "i|issuetype=s": setopt, + "w|watcher=s": setopt, + "r|reporter=s": setopt, + "f|queryfields=s": setopt, + "s|sort=s": setopt, + "l|limit|max_results=i": setopt, + "o|override=s%": &overrides, + "noedit": setopt, + "edit": setopt, + "m|comment=s": setopt, + "d|dir|directory=s": setopt, + }) - opts := make(map[string]string) - loadConfigs(opts) + if err := op.ProcessAll(os.Args[1:]); err != nil { + log.Error("%s", err) + usage(false) + } + args := op.Args + opts["overrides"] = overrides - // strip the "--" off the command line options - // and populate the opts that we pass to the cli ctor - for key, val := range args { - if val != nil && strings.HasPrefix(key, "--") { - opt := key[2:] - if opt == "override" { - for _, v := range val.([]string) { - if strings.Contains(v, "=") { - kv := strings.SplitN(v, "=", 2) - opts[kv[0]] = kv[1] - } 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) - case bool: - opts[opt] = fmt.Sprintf("%t", v) - } + command := "view" + if len(args) > 0 { + if alias, ok := jiraCommands[args[0]]; ok { + command = alias + args = args[1:] + } else if len(args) > 1 { + // look at second arg for "dups" and "blocks" commands + if alias, ok := jiraCommands[args[1]]; ok { + command = alias + args = append(args[:1], args[2:]...) } } } - // cant use proper [default:x] syntax in docopt - // because only want to default if the option is not - // already specified in some .jira.d/config.yml file - if _, ok := opts["user"]; !ok { - opts["user"] = user - } - if _, ok := opts["queryfields"]; !ok { - opts["queryfields"] = "summary,created,priority,status,reporter,assignee" - } - if _, ok := opts["directory"]; !ok { - opts["directory"] = fmt.Sprintf("%s/.jira.d/templates", home) - } - if _, ok := opts["sort"]; !ok { - opts["sort"] = "priority asc, created" - } - if _, ok := opts["max_results"]; !ok { - opts["max_results"] = defaultMaxResults - } + os.Setenv("JIRA_OPERATION", command) + loadConfigs(opts) if _, ok := opts["endpoint"]; !ok { log.Error("endpoint option required. Either use --endpoint or set a enpoint option in your ~/.jira.d/config.yml file") @@ -161,130 +212,90 @@ Command Options: log.Debug("opts: %s", opts) - validCommand := func(cmd string) bool { - if val, ok := args[cmd]; ok && val.(bool) { - return true - } - return false - } - - validOpt := func(opt string, dflt interface{}) interface{} { - if val, ok := opts[opt]; ok { - return val - } - if dflt == nil { - log.Error("Missing required option --%s or \"%s\" property override in the config file", opt, opt) - os.Exit(1) - } - return dflt - } - setEditing := func(dflt bool) { if dflt { - if val, ok := opts["noedit"]; ok && val == "true" { - opts["edit"] = "false" + if val, ok := opts["noedit"].(bool); ok && val { + opts["edit"] = false } else { - opts["edit"] = "true" + opts["edit"] = true } } else { - if val, ok := opts["edit"]; ok && val != "true" { - opts["edit"] = "false" + if val, ok := opts["edit"].(bool); ok && !val { + opts["edit"] = false } } } - if validCommand("login") { + var err error + switch command { + case "login": err = c.CmdLogin() - } else if validCommand("fields") { + case "fields": err = c.CmdFields() - } else if validCommand("ls") || validCommand("list") { + case "list": err = c.CmdList() - } else if validCommand("edit") { + case "edit": setEditing(true) - err = c.CmdEdit(args["ISSUE"].(string)) - } else if validCommand("editmeta") { - err = c.CmdEditMeta(args["ISSUE"].(string)) - } else if validCommand("transmeta") { - err = c.CmdTransitionMeta(args["ISSUE"].(string)) - } else if validCommand("issuelinktypes") { + err = c.CmdEdit(args[0]) + case "editmeta": + err = c.CmdEditMeta(args[0]) + case "transmeta": + err = c.CmdTransitionMeta(args[0]) + case "issuelinktypes": err = c.CmdIssueLinkTypes() - } else if validCommand("issuetypes") { - err = c.CmdIssueTypes(validOpt("project", nil).(string)) - } else if validCommand("createmeta") { - err = c.CmdCreateMeta( - validOpt("project", nil).(string), - validOpt("issuetype", "Bug").(string), - ) - } else if validCommand("create") { + case "issuetypes": + err = c.CmdIssueTypes() + case "createmeta": + err = c.CmdCreateMeta() + case "create": setEditing(true) - err = c.CmdCreate( - validOpt("project", nil).(string), - validOpt("issuetype", "Bug").(string), - ) - } else if validCommand("transitions") { - err = c.CmdTransitions(args["ISSUE"].(string)) - } else if validCommand("blocks") { - err = c.CmdBlocks( - args["BLOCKER"].(string), - args["ISSUE"].(string), - ) - } else if validCommand("dups") { - if err = c.CmdDups( - args["DUPLICATE"].(string), - args["ISSUE"].(string), - ); err == nil { + err = c.CmdCreate() + case "transitions": + err = c.CmdTransitions(args[0]) + case "blocks": + err = c.CmdBlocks(args[0], args[1]) + case "dups": + if err = c.CmdDups(args[0], args[1]); err == nil { opts["resolution"] = "Duplicate" - err = c.CmdTransition( - args["DUPLICATE"].(string), - "close", - ) + err = c.CmdTransition(args[0], "close") } - } else if validCommand("watch") { - err = c.CmdWatch( - args["ISSUE"].(string), - validOpt("watcher", user).(string), - ) - } else if validCommand("trans") || validCommand("transition") { + case "watch": + err = c.CmdWatch(args[0]) + case "transition": setEditing(true) - err = c.CmdTransition( - args["ISSUE"].(string), - args["TRANSITION"].(string), - ) - } else if validCommand("close") { + err = c.CmdTransition(args[0], args[1]) + case "close": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "close") - } else if validCommand("ack") { + err = c.CmdTransition(args[0], "close") + case "acknowledge": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "acknowledge") - } else if validCommand("reopen") { + err = c.CmdTransition(args[0], "acknowledge") + case "reopen": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "reopen") - } else if validCommand("resolve") { + err = c.CmdTransition(args[0], "reopen") + case "resolve": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "resolve") - } else if validCommand("start") { + err = c.CmdTransition(args[0], "resolve") + case "start": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "start") - } else if validCommand("stop") { + err = c.CmdTransition(args[0], "start") + case "stop": setEditing(false) - err = c.CmdTransition(args["ISSUE"].(string), "stop") - } else if validCommand("comment") { + err = c.CmdTransition(args[0], "stop") + case "comment": setEditing(true) - err = c.CmdComment(args["ISSUE"].(string)) - } else if validCommand("take") { - err = c.CmdAssign(args["ISSUE"].(string), opts["user"]) - } else if validCommand("browse") || validCommand("b") { - opts["browse"] = "true" - err = c.Browse(args["ISSUE"].(string)) - } else if validCommand("export-templates") { + err = c.CmdComment(args[0]) + case "take": + err = c.CmdAssign(args[0], opts["user"].(string)) + case "browse": + opts["browse"] = true + err = c.Browse(args[0]) + case "export-tempaltes": err = c.CmdExportTemplates() - } else if validCommand("assign") || validCommand("give") { - err = c.CmdAssign( - args["ISSUE"].(string), - args["ASSIGNEE"].(string), - ) - } else if val, ok := args["ISSUE"]; ok { - err = c.CmdView(val.(string)) + case "assign": + err = c.CmdAssign(args[0], args[1]) + default: + err = c.CmdView(args[0]) } if err != nil { @@ -293,73 +304,35 @@ Command Options: os.Exit(0) } -func parseYaml(file string, opts map[string]string) { +func parseYaml(file string, opts map[string]interface{}) { if fh, err := ioutil.ReadFile(file); err == nil { log.Debug("Found Config file: %s", file) yaml.Unmarshal(fh, &opts) } } -func populateEnv(args map[string]interface{}) { - foundOp := false - for key, val := range args { - if val != nil && strings.HasPrefix(key, "--") { - if key == "--override" { - for _, v := range val.([]string) { - if strings.Contains(v, "=") { - kv := strings.SplitN(v, "=", 2) - envName := fmt.Sprintf("JIRA_%s", strings.ToUpper(kv[0])) - os.Setenv(envName, kv[1]) - } else { - log.Error("Malformed override, expected KEY=VALUE, got %s", v) - os.Exit(1) - } - } - } else { - envName := fmt.Sprintf("JIRA_%s", strings.ToUpper(key[2:])) - switch v := val.(type) { - case []string: - os.Setenv(envName, strings.Join(v, ",")) - case string: - os.Setenv(envName, v) - case bool: - if v { - os.Setenv(envName, "1") - } else { - os.Setenv(envName, "0") - } - } - } - } else if val != nil { - // lower case strings are operations - if strings.ToLower(key) == key { - if key == "ls" && val.(bool) { - foundOp = true - os.Setenv("JIRA_OPERATION", "list") - } else if key == "b" && val.(bool) { - foundOp = true - os.Setenv("JIRA_OPERATION", "browse") - } else if key == "trans" && val.(bool) { - foundOp = true - os.Setenv("JIRA_OPERATION", "transition") - } else if key == "give" && val.(bool) { - foundOp = true - os.Setenv("JIRA_OPERATION", "assign") - } else if val.(bool) { - foundOp = true - os.Setenv("JIRA_OPERATION", key) - } - } else { - os.Setenv(fmt.Sprintf("JIRA_%s", key), val.(string)) - } +func populateEnv(opts map[string]interface{}) { + for k, v := range opts { + envName := fmt.Sprintf("JIRA_%s", strings.ToUpper(k)) + var val string + switch t := v.(type) { + case string: + val = t + case int, int8, int16, int32, int64: + val = fmt.Sprintf("%d", t) + case float32, float64: + val = fmt.Sprintf("%f", t) + case bool: + val = fmt.Sprintf("%t", t) + default: + val = fmt.Sprintf("%v", t) } - } - if !foundOp { - os.Setenv("JIRA_OPERATION", "view") + os.Setenv(envName, val) } } -func loadConfigs(opts map[string]string) { +func loadConfigs(opts map[string]interface{}) { + populateEnv(opts) paths := cli.FindParentPaths(".jira.d/config.yml") // prepend paths = append([]string{"/etc/jira-cli.yml"}, paths...) @@ -381,6 +354,7 @@ func loadConfigs(opts map[string]string) { os.Exit(1) } yaml.Unmarshal(stdout.Bytes(), &opts) + populateEnv(opts) } } }