From 230b52d528fbbc12ea2971a7cc1d3f3d5fe68d4d Mon Sep 17 00:00:00 2001 From: Mike Pountney Date: Thu, 24 Dec 2015 11:18:48 -0800 Subject: [PATCH 1/3] Add 'labels' command to set/add/remove labels This adds 'labels' command, which allows for the setting, addition and removal of labels on an issue. 'set' action resets the issue labels to the list provided. 'add' action adds the supplied labels to the issue 'remove' action removes the supplied labels from the issue The API already gracefully handles duplication, removal of non-existant labels, and the supplying of an empty list of labels (which is useful in the case of 'set') Eg jira labels TEST-123 add label1 label2 label3 jira labels TEST-123 remove label1 label2 jira labels TEST-123 set label1 label2 label3 jira labels TEST-123 set # clears any labels on the issue jira labels TEST-123 add # no-op jira labels TEST-123 remove # no-op This mirrors the functionality of the API. --- commands.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main/main.go | 10 ++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/commands.go b/commands.go index 64d25df4..fa74d25c 100644 --- a/commands.go +++ b/commands.go @@ -544,6 +544,71 @@ func (c *Cli) CmdComment(issue string) error { return nil } +func (c *Cli) CmdLabels(issue string, command string, labels []string) error { + log.Debug("label called") + + if command != "add" && command != "remove" && command != "set" { + return fmt.Errorf("command must be 'add', 'set' or 'remove': %q is invalid", command) + } + + handlePut := func(json string) error { + log.Debug("JSON: %s", json) + uri := fmt.Sprintf("%s/rest/api/2/issue/%s", c.endpoint, issue) + if c.getOptBool("dryrun", false) { + log.Debug("PUT: %s", json) + log.Debug("Dryrun mode, skipping POST") + return nil + } + resp, err := c.put(uri, json) + if err != nil { + return err + } + + if resp.StatusCode == 204 { + c.Browse(issue) + if !c.opts["quiet"].(bool) { + fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue) + } + 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 + } + } + + var labels_json string + var err error + if command == "set" { + labelsCommands := make([]map[string][]string, 1) + labelsCommands[0] = map[string][]string{ + "set": labels, + } + labels_json, err = jsonEncode(map[string]interface{}{ + "labels": labelsCommands, + }) + } else { + labelsCommands := make([]map[string]string, len(labels)) + for i, label := range labels { + labelCommandMap := map[string]string{ + command: label, + } + labelsCommands[i] = labelCommandMap + } + labels_json, err = jsonEncode(map[string]interface{}{ + "labels": labelsCommands, + }) + } + if err != nil { + return err + } + json := fmt.Sprintf("{ \"update\": %s }", labels_json) + return handlePut(json) + +} + func (c *Cli) CmdAssign(issue string, user string) error { log.Debug("assign called") diff --git a/main/main.go b/main/main.go index 17f6f5c3..8b142356 100644 --- a/main/main.go +++ b/main/main.go @@ -14,8 +14,8 @@ import ( ) var ( - log = logging.MustGetLogger("jira") - format = "%{color}%{time:2006-01-02T15:04:05.000Z07:00} %{level:-5s} [%{shortfile}]%{color:reset} %{message}" + log = logging.MustGetLogger("jira") + format = "%{color}%{time:2006-01-02T15:04:05.000Z07:00} %{level:-5s} [%{shortfile}]%{color:reset} %{message}" ) func main() { @@ -65,6 +65,7 @@ Usage: jira start ISSUE [--edit] jira stop ISSUE [--edit] jira comment ISSUE [--noedit] + jira labels ISSUE set,add,remove [LABEL] ... jira take ISSUE jira (assign|give) ISSUE ASSIGNEE jira fields @@ -136,6 +137,8 @@ Command Options: "start": "start", "stop": "stop", "comment": "comment", + "label": "labels", + "labels": "labels", "take": "take", "assign": "assign", "give": "assign", @@ -377,6 +380,9 @@ Command Options: requireArgs(1) setEditing(true) err = c.CmdComment(args[0]) + case "labels": + requireArgs(2) + err = c.CmdLabels(args[0], args[1], args[2:]) case "take": requireArgs(1) err = c.CmdAssign(args[0], opts["user"].(string)) From 40a7c653661ba9c3f36c74ace20182e7dbfe2899 Mon Sep 17 00:00:00 2001 From: Mike Pountney Date: Sun, 3 Jan 2016 20:10:12 -0800 Subject: [PATCH 2/3] Tweak CmdLabels args so that magic happens with CLI The CLI looks for commands (like 'labels') in the first two positional args. This is how commands like 'BLOCKER blocks ISSUE' work. As per @coryb's comments in #21 - this allows us to support set/add/remove in a consistent way for other types: components for example. This commit rearranges the command to be as follows: jira (set/add/remove) labels ISSUE LABELS... The options to CmdLabels have been reordered accordingly. --- commands.go | 2 +- main/main.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/commands.go b/commands.go index 721648d5..e3c31476 100644 --- a/commands.go +++ b/commands.go @@ -542,7 +542,7 @@ func (c *Cli) CmdComment(issue string) error { return nil } -func (c *Cli) CmdLabels(issue string, command string, labels []string) error { +func (c *Cli) CmdLabels(command string, issue string, labels []string) error { log.Debug("label called") if command != "add" && command != "remove" && command != "set" { diff --git a/main/main.go b/main/main.go index 8b142356..4821320b 100644 --- a/main/main.go +++ b/main/main.go @@ -65,7 +65,7 @@ Usage: jira start ISSUE [--edit] jira stop ISSUE [--edit] jira comment ISSUE [--noedit] - jira labels ISSUE set,add,remove [LABEL] ... + jira (set,add,remove) labels ISSUE [LABEL] ... jira take ISSUE jira (assign|give) ISSUE ASSIGNEE jira fields @@ -219,6 +219,7 @@ Command Options: 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:]...) @@ -382,7 +383,10 @@ Command Options: err = c.CmdComment(args[0]) case "labels": requireArgs(2) - err = c.CmdLabels(args[0], args[1], args[2:]) + action := args[0] + issue := args[1] + labels := args[2:] + err = c.CmdLabels(action, issue, labels) case "take": requireArgs(1) err = c.CmdAssign(args[0], opts["user"].(string)) From 303784fd56f88632db730f39971a1afc65d06892 Mon Sep 17 00:00:00 2001 From: Mike Pountney Date: Sun, 3 Jan 2016 20:19:07 -0800 Subject: [PATCH 3/3] Correct naming of parameter: set/add/remove are actions. 'command' is not approprirate for the set/add/remove operations, and is confusing. Rename to 'action' to remove this confusion. --- commands.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/commands.go b/commands.go index e3c31476..839e5684 100644 --- a/commands.go +++ b/commands.go @@ -542,11 +542,11 @@ func (c *Cli) CmdComment(issue string) error { return nil } -func (c *Cli) CmdLabels(command string, issue string, labels []string) error { +func (c *Cli) CmdLabels(action string, issue string, labels []string) error { log.Debug("label called") - if command != "add" && command != "remove" && command != "set" { - return fmt.Errorf("command must be 'add', 'set' or 'remove': %q is invalid", command) + if action != "add" && action != "remove" && action != "set" { + return fmt.Errorf("action must be 'add', 'set' or 'remove': %q is invalid", action) } handlePut := func(json string) error { @@ -579,24 +579,24 @@ func (c *Cli) CmdLabels(command string, issue string, labels []string) error { var labels_json string var err error - if command == "set" { - labelsCommands := make([]map[string][]string, 1) - labelsCommands[0] = map[string][]string{ + if action == "set" { + labelsActions := make([]map[string][]string, 1) + labelsActions[0] = map[string][]string{ "set": labels, } labels_json, err = jsonEncode(map[string]interface{}{ - "labels": labelsCommands, + "labels": labelsActions, }) } else { - labelsCommands := make([]map[string]string, len(labels)) + labelsActions := make([]map[string]string, len(labels)) for i, label := range labels { - labelCommandMap := map[string]string{ - command: label, + labelActionMap := map[string]string{ + action: label, } - labelsCommands[i] = labelCommandMap + labelsActions[i] = labelActionMap } labels_json, err = jsonEncode(map[string]interface{}{ - "labels": labelsCommands, + "labels": labelsActions, }) } if err != nil {