func Run() { var err error logging.SetLevel(logging.NOTICE, "") 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-ui ls <Query Options> jira-ui ISSUE jira-ui General Options: -e --endpoint=URI URI to use for jira -h --help Show this usage -u --user=USER Username to use for authenticaion -v --verbose Increase output logging --skiplogin Skip the login check. You must have a valid session token (eg via 'jira login') --version Print version Ticket View Options: -t --template=FILE Template file to use for viewing tickets -m --max_wrap=VAL Maximum word-wrap width when viewing ticket text (0 disables) Query Options: -q --query=JQL Jira Query Language expression for the search -f --queryfields=FIELDS Fields that are used in "list" view `) printer(output) } jiraCommands := map[string]string{ "list": "list", "ls": "list", "password": "******", "passwd": "password", } cliOpts = make(map[string]interface{}) setopt := func(name string, value interface{}) { cliOpts[name] = value } op := optigo.NewDirectAssignParser(map[string]interface{}{ "h|help": usage, "version": func() { fmt.Println(fmt.Sprintf("version: %s", VERSION)) os.Exit(0) }, "v|verbose+": func() { logging.SetLevel(logging.GetLevel("")+1, "") }, "u|user=s": setopt, "endpoint=s": setopt, "q|query=s": setopt, "f|queryfields=s": setopt, "t|template=s": setopt, "m|max_wrap=i": setopt, "skip_login": setopt, }) if err := op.ProcessAll(os.Args[1:]); err != nil { log.Error("%s", err) usage(false) } args := op.Args var command string if len(args) > 0 { if alias, ok := jiraCommands[args[0]]; ok { command = alias args = args[1:] } else { command = "view" args = args[0:] } } else { command = "toplevel" } requireArgs := func(count int) { if len(args) < count { log.Error("Not enough arguments. %d required, %d provided", count, len(args)) usage(false) } } if val, ok := cliOpts["skip_login"]; !ok || !val.(bool) { err = ensureLoggedIntoJira() if err != nil { log.Error("Login failed. Aborting") os.Exit(2) } } err = ui.Init() if err != nil { panic(err) } defer ui.Close() registerKeyboardHandlers() ticketQueryPage = new(QueryPage) passwordInputBox = new(PasswordInputBox) helpPage = new(HelpPage) commandBar = new(CommandBar) switch command { case "list": ticketListPage = new(TicketListPage) if query := cliOpts["query"]; query == nil { log.Error("Must supply a --query option to %q", command) os.Exit(1) } else { ticketListPage.ActiveQuery.JQL = query.(string) ticketListPage.ActiveQuery.Name = "adhoc" currentPage = ticketListPage } case "view": requireArgs(1) p := new(TicketShowPage) p.TicketId = args[0] currentPage = p case "toplevel": currentPage = ticketQueryPage case "password": currentPage = passwordInputBox default: log.Error("Unknown command %s", command) os.Exit(1) } for exitNow != true { currentPage.Create() ui.Loop() } }
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") defaultQueryFields := "summary,created,priority,status,reporter,assignee" defaultSort := "priority asc, created" 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 (ls|list) <Query Options> jira view ISSUE jira edit [--noedit] <Edit Options> [ISSUE | <Query Options>] jira create [--noedit] [-p PROJECT] <Create Options> jira DUPLICATE dups ISSUE jira BLOCKER blocks ISSUE jira watch ISSUE [-w WATCHER] jira (trans|transition) TRANSITION ISSUE [--noedit] <Edit Options> jira ack ISSUE [--edit] <Edit Options> jira close ISSUE [--edit] <Edit Options> jira resolve ISSUE [--edit] <Edit Options> jira reopen ISSUE [--edit] <Edit Options> jira start ISSUE [--edit] <Edit Options> jira stop ISSUE [--edit] <Edit Options> jira comment ISSUE [--noedit] <Edit Options> 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: -b --browse Open your browser to the Jira issue -e --endpoint=URI URI to use for jira -h --help Show this usage -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 Print version Query Options: -a --assignee=USER Username assigned the issue -c --component=COMPONENT Component to Search for -f --queryfields=FIELDS Fields that are used in "list" template: (default: %s) -i --issuetype=ISSUETYPE The Issue Type -l --limit=VAL Maximum number of results to return in query (default: %d) -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: %s) -w --watcher=USER Watcher to add to issue (default: %s) or Watcher to search for Edit Options: -m --comment=COMMENT Comment message for transition -o --override=KEY=VAL Set custom key/value pairs Create Options: -i --issuetype=ISSUETYPE Jira Issue Type (default: Bug) -m --comment=COMMENT Comment message for transition -o --override=KEY=VAL Set custom key/value pairs Command Options: -d --directory=DIR Directory to export templates to (default: %s) `, user, defaultQueryFields, defaultMaxResults, defaultSort, user, fmt.Sprintf("%s/.jira.d/templates", home)) printer(output) } 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": "******", } defaults := map[string]interface{}{ "user": user, "queryfields": defaultQueryFields, "directory": fmt.Sprintf("%s/.jira.d/templates", home), "sort": defaultSort, "max_results": defaultMaxResults, } opts := make(map[string]interface{}) overrides := make(map[string]string) setopt := func(name string, value interface{}) { opts[name] = value } op := optigo.NewDirectAssignParser(map[string]interface{}{ "h|help": usage, "version": func() { fmt.Println("version: 0.0.12") os.Exit(0) }, "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, }) if err := op.ProcessAll(os.Args[1:]); err != nil { log.Error("%s", err) usage(false) } args := op.Args for k, v := range overrides { opts[k] = v } var command string 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:]...) } } } if command == "" { command = args[0] args = args[1:] } os.Setenv("JIRA_OPERATION", command) loadConfigs(opts) // check to see if it was set in the configs: if value, ok := opts["command"].(string); ok { command = value } else if _, ok := jiraCommands[command]; !ok || command == "" { args = append([]string{command}, args...) command = "view" } // apply defaults for k, v := range defaults { if _, ok := opts[k]; !ok { log.Debug("Setting %q to %#v from defaults", k, v) opts[k] = v } } log.Debug("opts: %v", opts) log.Debug("args: %v", args) 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") os.Exit(1) } c := cli.New(opts) log.Debug("opts: %s", opts) setEditing := func(dflt bool) { log.Debug("Default Editing: %t", dflt) if dflt { if val, ok := opts["noedit"].(bool); ok && val { log.Debug("Setting edit = false") opts["edit"] = false } else { log.Debug("Setting edit = true") opts["edit"] = true } } else { if _, ok := opts["edit"].(bool); !ok { log.Debug("Setting edit = %t", dflt) opts["edit"] = dflt } } } var err error switch command { case "login": err = c.CmdLogin() case "fields": err = c.CmdFields() case "list": err = c.CmdList() case "edit": setEditing(true) if len(args) > 0 { err = c.CmdEdit(args[0]) } else { var data interface{} if data, err = c.FindIssues(); err == nil { issues := data.(map[string]interface{})["issues"].([]interface{}) for _, issue := range issues { if err = c.CmdEdit(issue.(map[string]interface{})["key"].(string)); err != nil { switch err.(type) { case cli.NoChangesFound: log.Warning("No Changes found: %s", err) err = nil continue } break } } } } case "editmeta": err = c.CmdEditMeta(args[0]) case "transmeta": err = c.CmdTransitionMeta(args[0]) case "issuelinktypes": err = c.CmdIssueLinkTypes() case "issuetypes": err = c.CmdIssueTypes() case "createmeta": err = c.CmdCreateMeta() case "create": setEditing(true) 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[0], "close") } case "watch": err = c.CmdWatch(args[0]) case "transition": setEditing(true) err = c.CmdTransition(args[0], args[1]) case "close": setEditing(false) err = c.CmdTransition(args[0], "close") case "acknowledge": setEditing(false) err = c.CmdTransition(args[0], "acknowledge") case "reopen": setEditing(false) err = c.CmdTransition(args[0], "reopen") case "resolve": setEditing(false) err = c.CmdTransition(args[0], "resolve") case "start": setEditing(false) err = c.CmdTransition(args[0], "start") case "stop": setEditing(false) err = c.CmdTransition(args[0], "stop") case "comment": setEditing(true) 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() case "assign": err = c.CmdAssign(args[0], args[1]) case "view": err = c.CmdView(args[0]) default: log.Error("Unknown command %s", command) os.Exit(1) } if err != nil { log.Error("%s", err) os.Exit(1) } os.Exit(0) }
func main() { logBackend := logging.NewLogBackend(os.Stderr, "", 0) format := os.Getenv("JIRA_LOG_FORMAT") if format == "" { format = defaultFormat } logging.SetBackend( logging.NewBackendFormatter( logBackend, logging.MustStringFormatter(format), ), ) logging.SetLevel(logging.NOTICE, "") user := os.Getenv("USER") home := os.Getenv("HOME") defaultQueryFields := "summary,created,updated,priority,status,reporter,assignee" defaultSort := "priority asc, created" 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 (ls|list) <Query Options> jira view ISSUE jira worklog ISSUE jira addworklog ISSUE time comment jira edit [--noedit] <Edit Options> [ISSUE | <Query Options>] jira create [--noedit] [-p PROJECT] <Create Options> jira DUPLICATE dups ISSUE jira BLOCKER blocks ISSUE jira vote ISSUE [--down] jira watch ISSUE [-w WATCHER] [--remove] jira (trans|transition) TRANSITION ISSUE [--noedit] <Edit Options> jira ack ISSUE [--edit] <Edit Options> jira close ISSUE [--edit] <Edit Options> jira resolve ISSUE [--edit] <Edit Options> jira reopen ISSUE [--edit] <Edit Options> jira start ISSUE [--edit] <Edit Options> jira stop ISSUE [--edit] <Edit Options> jira todo ISSUE [--edit] <Edit Options> jira done ISSUE [--edit] <Edit Options> jira prog|progress|in-progress [--edit] <Edit Options> jira comment ISSUE [--noedit] <Edit Options> jira (set,add,remove) labels ISSUE [LABEL] ... jira take ISSUE jira (assign|give) ISSUE ASSIGNEE jira fields jira issuelinktypes jira transmeta ISSUE jira editmeta ISSUE jira add component [-p PROJECT] NAME DESCRIPTION LEAD jira components [-p PROJECT] 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 logout jira request [-M METHOD] URI [DATA] jira ISSUE General Options: -b --browse Open your browser to the Jira issue -e --endpoint=URI URI to use for jira -k --insecure disable TLS certificate verification -h --help Show this usage -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 Print version Query Options: -a --assignee=USER Username assigned the issue -c --component=COMPONENT Component to Search for -f --queryfields=FIELDS Fields that are used in "list" template: (default: %s) -i --issuetype=ISSUETYPE The Issue Type -l --limit=VAL Maximum number of results to return in query (default: %d) -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: %s) -w --watcher=USER Watcher to add to issue (default: %s) or Watcher to search for Edit Options: -m --comment=COMMENT Comment message for transition -o --override=KEY=VAL Set custom key/value pairs Create Options: -i --issuetype=ISSUETYPE Jira Issue Type (default: Bug) -m --comment=COMMENT Comment message for transition -o --override=KEY=VAL Set custom key/value pairs Command Options: -d --directory=DIR Directory to export templates to (default: %s) `, user, defaultQueryFields, defaultMaxResults, defaultSort, user, fmt.Sprintf("%s/.jira.d/templates", home)) printer(output) } 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", "todo": "todo", "done": "done", "prog": "in-progress", "progress": "in-progress", "in-progress": "in-progress", "comment": "comment", "label": "labels", "labels": "labels", "component": "component", "components": "components", "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": "******", "logout": "logout", "req": "request", "request": "request", "vote": "vote", "worklog": "worklog", "addworklog": "addworklog", } defaults := map[string]interface{}{ "user": user, "queryfields": defaultQueryFields, "directory": fmt.Sprintf("%s/.jira.d/templates", home), "sort": defaultSort, "max_results": defaultMaxResults, "method": "GET", "quiet": false, } opts := make(map[string]interface{}) setopt := func(name string, value interface{}) { opts[name] = value } op := optigo.NewDirectAssignParser(map[string]interface{}{ "h|help": usage, "version": func() { fmt.Println(fmt.Sprintf("version: %s", jira.VERSION)) os.Exit(0) }, "v|verbose+": func() { logging.SetLevel(logging.GetLevel("")+1, "") }, "dryrun": setopt, "b|browse": setopt, "editor=s": setopt, "u|user=s": setopt, "endpoint=s": setopt, "k|insecure": 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, "remove": setopt, "r|reporter=s": setopt, "f|queryfields=s": setopt, "x|expand=s": setopt, "s|sort=s": setopt, "l|limit|max_results=i": setopt, "o|override=s%": &opts, "noedit": setopt, "edit": setopt, "m|comment=s": setopt, "d|dir|directory=s": setopt, "M|method=s": setopt, "S|saveFile=s": setopt, "Q|quiet": setopt, "down": setopt, }) if err := op.ProcessAll(os.Args[1:]); err != nil { log.Errorf("%s", err) usage(false) } args := op.Args var command string 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 // also for 'set/add/remove' actions like 'labels' if alias, ok := jiraCommands[args[1]]; ok { command = alias args = append(args[:1], args[2:]...) } } } if command == "" && len(args) > 0 { command = args[0] args = args[1:] } os.Setenv("JIRA_OPERATION", command) loadConfigs(opts) // check to see if it was set in the configs: if value, ok := opts["command"].(string); ok { command = value } else if _, ok := jiraCommands[command]; !ok || command == "" { if command != "" { args = append([]string{command}, args...) } command = "view" } // apply defaults for k, v := range defaults { if _, ok := opts[k]; !ok { log.Debugf("Setting %q to %#v from defaults", k, v) opts[k] = v } } log.Debugf("opts: %v", opts) log.Debugf("args: %v", args) if _, ok := opts["endpoint"]; !ok { log.Errorf("endpoint option required. Either use --endpoint or set a endpoint option in your ~/.jira.d/config.yml file") os.Exit(1) } c := jira.New(opts) log.Debugf("opts: %s", opts) setEditing := func(dflt bool) { log.Debugf("Default Editing: %t", dflt) if dflt { if val, ok := opts["noedit"].(bool); ok && val { log.Debugf("Setting edit = false") opts["edit"] = false } else { log.Debugf("Setting edit = true") opts["edit"] = true } } else { if _, ok := opts["edit"].(bool); !ok { log.Debugf("Setting edit = %t", dflt) opts["edit"] = dflt } } } requireArgs := func(count int) { if len(args) < count { log.Errorf("Not enough arguments. %d required, %d provided", count, len(args)) usage(false) } } var err error switch command { case "login": err = c.CmdLogin() case "logout": err = c.CmdLogout() case "fields": err = c.CmdFields() case "list": err = c.CmdList() case "edit": setEditing(true) if len(args) > 0 { err = c.CmdEdit(args[0]) } else { var data interface{} if data, err = c.FindIssues(); err == nil { issues := data.(map[string]interface{})["issues"].([]interface{}) for _, issue := range issues { if err = c.CmdEdit(issue.(map[string]interface{})["key"].(string)); err != nil { switch err.(type) { case jira.NoChangesFound: log.Warning("No Changes found: %s", err) err = nil continue } break } } } } case "editmeta": requireArgs(1) err = c.CmdEditMeta(args[0]) case "transmeta": requireArgs(1) err = c.CmdTransitionMeta(args[0]) case "issuelinktypes": err = c.CmdIssueLinkTypes() case "issuetypes": err = c.CmdIssueTypes() case "createmeta": err = c.CmdCreateMeta() case "create": setEditing(true) err = c.CmdCreate() case "transitions": requireArgs(1) err = c.CmdTransitions(args[0]) case "blocks": requireArgs(2) err = c.CmdBlocks(args[0], args[1]) case "dups": requireArgs(2) if err = c.CmdDups(args[0], args[1]); err == nil { opts["resolution"] = "Duplicate" err = c.CmdTransition(args[0], "close") } case "watch": requireArgs(1) watcher := c.GetOptString("watcher", opts["user"].(string)) remove := c.GetOptBool("remove", false) err = c.CmdWatch(args[0], watcher, remove) case "transition": requireArgs(2) setEditing(true) err = c.CmdTransition(args[1], args[0]) case "close": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "close") case "acknowledge": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "acknowledge") case "reopen": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "reopen") case "resolve": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "resolve") case "start": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "start") case "stop": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "stop") case "todo": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "To Do") case "done": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "Done") case "in-progress": requireArgs(1) setEditing(false) err = c.CmdTransition(args[0], "In Progress") case "comment": requireArgs(1) setEditing(true) err = c.CmdComment(args[0]) case "labels": requireArgs(2) action := args[0] issue := args[1] labels := args[2:] err = c.CmdLabels(action, issue, labels) case "component": requireArgs(2) action := args[0] project := opts["project"].(string) name := args[1] var lead string var description string if len(args) > 2 { description = args[2] } if len(args) > 3 { lead = args[2] } err = c.CmdComponent(action, project, name, description, lead) case "components": project := opts["project"].(string) err = c.CmdComponents(project) case "take": requireArgs(1) err = c.CmdAssign(args[0], opts["user"].(string)) case "browse": requireArgs(1) opts["browse"] = true err = c.Browse(args[0]) case "export-templates": err = c.CmdExportTemplates() case "assign": requireArgs(2) err = c.CmdAssign(args[0], args[1]) case "view": requireArgs(1) err = c.CmdView(args[0]) case "worklog": requireArgs(1) err = c.CmdWorklogs(args[0]) case "addworklog": requireArgs(4) timeInSeconds, err := strconv.Atoi(args[1]) if err == nil { err = c.CmdNewWorklog(args[0], timeInSeconds, args[2], args[3]) } case "vote": requireArgs(1) if val, ok := opts["down"]; ok { err = c.CmdVote(args[0], !val.(bool)) } else { err = c.CmdVote(args[0], true) } case "request": requireArgs(1) data := "" if len(args) > 1 { data = args[1] } err = c.CmdRequest(args[0], data) default: log.Errorf("Unknown command %s", command) os.Exit(1) } if err != nil { log.Errorf("%s", err) os.Exit(1) } os.Exit(0) }