From cc90610e72631fdd40d3b174cf9959fc3dfd527a Mon Sep 17 00:00:00 2001 From: Cory Bennett Date: Sat, 19 Aug 2017 22:57:41 -0500 Subject: [PATCH] add `component add` command --- cmd/jira/main.go | 21 ++--------- component.go | 34 +++++++++++++++++ jiracli/commands.go | 44 ---------------------- jiracli/componentAdd.go | 81 +++++++++++++++++++++++++++++++++++++++++ jiracli/templates.go | 8 ++++ jiradata/providers.go | 4 +- 6 files changed, 129 insertions(+), 63 deletions(-) create mode 100644 component.go create mode 100644 jiracli/componentAdd.go diff --git a/cmd/jira/main.go b/cmd/jira/main.go index 9da8ba96..c30ebed8 100644 --- a/cmd/jira/main.go +++ b/cmd/jira/main.go @@ -229,6 +229,10 @@ func main() { Command: "unassign", Entry: cli.CmdUnassignRegistry(), }, + jiracli.CommandRegistry{ + Command: "component add", + Entry: cli.CmdComponentAddRegistry(), + }, } cli.Register(app, registry) @@ -247,7 +251,6 @@ func main() { } // Usage: - // jira add component [-p PROJECT] NAME DESCRIPTION LEAD // jira components [-p PROJECT] // jira issuetypes [-p PROJECT] // jira export-templates [-d DIR] [-t template] @@ -298,9 +301,7 @@ func main() { // } // jiraCommands := map[string]string{ - // "component": "component", // "components": "components", - // "give": "assign", // "issuetypes": "issuetypes", // "export-templates": "export-templates", // "browse": "browse", @@ -453,20 +454,6 @@ func main() { // switch command { // case "issuetypes": // err = c.CmdIssueTypes() - // 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) diff --git a/component.go b/component.go new file mode 100644 index 00000000..a5b7fc84 --- /dev/null +++ b/component.go @@ -0,0 +1,34 @@ +package jira + +import ( + "bytes" + "encoding/json" + "fmt" + + "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" +) + +type ComponentProvider interface { + ProvideComponent() *jiradata.Component +} + +// https://docs.atlassian.com/jira/REST/cloud/#api/2/component-createComponent +func (j *Jira) CreateComponent(cp ComponentProvider) (*jiradata.Component, error) { + req := cp.ProvideComponent() + encoded, err := json.Marshal(req) + if err != nil { + return nil, err + } + uri := fmt.Sprintf("%s/rest/api/2/component", j.Endpoint) + resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode == 201 { + results := &jiradata.Component{} + return results, readJSON(resp.Body, results) + } + return nil, responseError(resp) +} diff --git a/jiracli/commands.go b/jiracli/commands.go index 8839708a..75223ed7 100644 --- a/jiracli/commands.go +++ b/jiracli/commands.go @@ -116,50 +116,6 @@ func (jc *JiraCli) Register(app *kingpin.Application, reg []CommandRegistry) { // return runTemplate(c.getTemplate("components"), data, nil) // } -// // CmdComponent will add a new component to given project -// func (c *Cli) CmdComponent(action string, project string, name string, desc string, lead string) error { -// log.Debugf("component called") - -// switch action { -// case "add": -// default: -// return fmt.Errorf("CmdComponent: %q is not a valid action", action) -// } - -// json, err := jsonEncode(map[string]interface{}{ -// "name": name, -// "description": desc, -// "leadUserName": lead, -// "project": project, -// }) -// if err != nil { -// return err -// } - -// uri := fmt.Sprintf("%s/rest/api/2/component", c.endpoint) -// if c.getOptBool("dryrun", false) { -// log.Debugf("POST: %s", json) -// log.Debugf("Dryrun mode, skipping POST") -// return nil -// } -// resp, err := c.post(uri, json) -// if err != nil { -// return err -// } -// if resp.StatusCode == 201 { -// if !c.GetOptBool("quiet", false) { -// fmt.Printf("OK %s %s\n", project, name) -// } -// } else { -// logBuffer := bytes.NewBuffer(make([]byte, 0)) -// resp.Write(logBuffer) -// err := fmt.Errorf("Unexpected Response From POST") -// log.Errorf("%s:\n%s", err, logBuffer) -// return err -// } -// return nil -// } - // // CmdExportTemplates will export the default templates to the template directory. // func (c *Cli) CmdExportTemplates() error { // dir := c.opts["directory"].(string) diff --git a/jiracli/componentAdd.go b/jiracli/componentAdd.go new file mode 100644 index 00000000..1c3707fd --- /dev/null +++ b/jiracli/componentAdd.go @@ -0,0 +1,81 @@ +package jiracli + +import ( + "fmt" + + "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" + kingpin "gopkg.in/alecthomas/kingpin.v2" +) + +type ComponentAddOptions struct { + GlobalOptions + Overrides map[string]string +} + +func (jc *JiraCli) CmdComponentAddRegistry() *CommandRegistryEntry { + opts := ComponentAddOptions{ + GlobalOptions: GlobalOptions{ + Template: "component-add", + }, + Overrides: map[string]string{}, + } + + return &CommandRegistryEntry{ + "ComponentAdd issue", + func() error { + return jc.CmdComponentAdd(&opts) + }, + func(cmd *kingpin.CmdClause) error { + return jc.CmdComponentAddUsage(cmd, &opts) + }, + } +} + +func (jc *JiraCli) CmdComponentAddUsage(cmd *kingpin.CmdClause, opts *ComponentAddOptions) error { + if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { + return err + } + jc.EditorUsage(cmd, &opts.GlobalOptions) + jc.TemplateUsage(cmd, &opts.GlobalOptions) + cmd.Flag("noedit", "Disable opening the editor").BoolVar(&opts.SkipEditing) + cmd.Flag("project", "project to create component in").Short('p').PreAction(func(ctx *kingpin.ParseContext) error { + opts.Overrides["project"] = flagValue(ctx, "project") + return nil + }).String() + cmd.Flag("name", "name of component").Short('n').PreAction(func(ctx *kingpin.ParseContext) error { + opts.Overrides["name"] = flagValue(ctx, "name") + return nil + }).String() + cmd.Flag("description", "description of component").Short('d').PreAction(func(ctx *kingpin.ParseContext) error { + opts.Overrides["description"] = flagValue(ctx, "description") + return nil + }).String() + cmd.Flag("lead", "person that acts as lead for component").Short('l').PreAction(func(ctx *kingpin.ParseContext) error { + opts.Overrides["lead"] = flagValue(ctx, "lead") + return nil + }).String() + return nil +} + +// CmdComponentAdd sends the provided overrides to the "component-add" template for editing, then +// will parse the edited document as YAML and submit the document to jira. +func (jc *JiraCli) CmdComponentAdd(opts *ComponentAddOptions) error { + input := struct { + Overrides map[string]string + }{ + opts.Overrides, + } + + var err error + component := &jiradata.Component{} + err = jc.editLoop(&opts.GlobalOptions, &input, component, func() error { + component, err = jc.CreateComponent(component) + return err + }) + if err != nil { + return err + } + + fmt.Printf("OK %s %s\n", component.Project, component.Name) + return nil +} diff --git a/jiracli/templates.go b/jiracli/templates.go index 3820e524..f4a7b8ff 100644 --- a/jiracli/templates.go +++ b/jiracli/templates.go @@ -178,6 +178,7 @@ func (jc *JiraCli) runTemplate(templateName string, data interface{}, out io.Wri } var allTemplates = map[string]string{ + "component-add": defaultComponentAddTemplate, "debug": defaultDebugTemplate, "fields": defaultDebugTemplate, "editmeta": defaultDebugTemplate, @@ -298,6 +299,13 @@ const defaultTransitionsTemplate = `{{ range .transitions }}{{.id }}: {{.name}} const defaultComponentsTemplate = `{{ range . }}{{.id }}: {{.name}} {{end}}` +const defaultComponentAddTemplate = `{{/* compoinent add template */ -}} +project: {{or .overrides.project ""}} +name: {{or .overrides.name ""}} +description: {{or .overrides.description ""}} +leadUserName: {{or .overrides.lead ""}} +` + const defaultIssuetypesTemplate = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}} {{end}}{{end}}` diff --git a/jiradata/providers.go b/jiradata/providers.go index dc29c0c3..c181c0bf 100644 --- a/jiradata/providers.go +++ b/jiradata/providers.go @@ -22,6 +22,6 @@ func (c *Comment) ProvideComment() *Comment { return c } -func (u *User) ProvideUser() *User { - return u +func (c *Component) ProvideComponent() *Component { + return c }