diff --git a/cmd/jira/main.go b/cmd/jira/main.go index c30ebed8..8a961dab 100644 --- a/cmd/jira/main.go +++ b/cmd/jira/main.go @@ -233,6 +233,10 @@ func main() { Command: "component add", Entry: cli.CmdComponentAddRegistry(), }, + jiracli.CommandRegistry{ + Command: "components", + Entry: cli.CmdComponentsRegistry(), + }, } cli.Register(app, registry) @@ -251,7 +255,6 @@ func main() { } // Usage: - // jira components [-p PROJECT] // jira issuetypes [-p PROJECT] // jira export-templates [-d DIR] [-t template] // jira (b|browse) ISSUE @@ -301,7 +304,6 @@ func main() { // } // jiraCommands := map[string]string{ - // "components": "components", // "issuetypes": "issuetypes", // "export-templates": "export-templates", // "browse": "browse", @@ -454,9 +456,6 @@ func main() { // switch command { // case "issuetypes": // err = c.CmdIssueTypes() - // case "components": - // project := opts["project"].(string) - // err = c.CmdComponents(project) // case "browse": // requireArgs(1) // opts["browse"] = true diff --git a/jiracli/cli.go b/jiracli/cli.go index 0b12d6f4..fe481d3d 100644 --- a/jiracli/cli.go +++ b/jiracli/cli.go @@ -222,7 +222,7 @@ func (jc *JiraCli) editLoop(opts *GlobalOptions, input interface{}, output inter // etc. We need to do this because jira will reject json documents // with empty arrays, or empty strings typically. So here we process // the data to a raw interface{} then we fixup the yaml parsed - // inferface, then we serialize to a new yaml document ... then is + // interface, then we serialize to a new yaml document ... then is // parsed as the original document to populate the output struct. Phew. var raw interface{} if err := yaml.Unmarshal(data, &raw); err != nil { diff --git a/jiracli/commands.go b/jiracli/commands.go index 75223ed7..be05c75b 100644 --- a/jiracli/commands.go +++ b/jiracli/commands.go @@ -105,17 +105,6 @@ func (jc *JiraCli) Register(app *kingpin.Application, reg []CommandRegistry) { // return "" // } -// // CmdComponents sends component data for given project and sends to the "components" template -// func (c *Cli) CmdComponents(project string) error { -// log.Debugf("Components called") -// uri := fmt.Sprintf("%s/rest/api/2/project/%s/components", c.endpoint, project) -// data, err := responseToJSON(c.get(uri)) -// if err != nil { -// return err -// } -// return runTemplate(c.getTemplate("components"), data, 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 index 1c3707fd..bed41d79 100644 --- a/jiracli/componentAdd.go +++ b/jiracli/componentAdd.go @@ -9,7 +9,7 @@ import ( type ComponentAddOptions struct { GlobalOptions - Overrides map[string]string + jiradata.Component } func (jc *JiraCli) CmdComponentAddRegistry() *CommandRegistryEntry { @@ -17,11 +17,10 @@ func (jc *JiraCli) CmdComponentAddRegistry() *CommandRegistryEntry { GlobalOptions: GlobalOptions{ Template: "component-add", }, - Overrides: map[string]string{}, } return &CommandRegistryEntry{ - "ComponentAdd issue", + "Add component", func() error { return jc.CmdComponentAdd(&opts) }, @@ -38,38 +37,21 @@ func (jc *JiraCli) CmdComponentAddUsage(cmd *kingpin.CmdClause, opts *ComponentA 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() + cmd.Flag("project", "project to create component in").Short('p').StringVar(&opts.Project) + cmd.Flag("name", "name of component").Short('n').StringVar(&opts.Name) + cmd.Flag("description", "description of component").Short('d').StringVar(&opts.Description) + cmd.Flag("lead", "person that acts as lead for component").Short('l').StringVar(&opts.LeadUserName) 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) + var resp *jiradata.Component + err = jc.editLoop(&opts.GlobalOptions, &opts.Component, component, func() error { + resp, err = jc.CreateComponent(component) return err }) if err != nil { diff --git a/jiracli/components.go b/jiracli/components.go new file mode 100644 index 00000000..d3763d65 --- /dev/null +++ b/jiracli/components.go @@ -0,0 +1,52 @@ +package jiracli + +import ( + "fmt" + + kingpin "gopkg.in/alecthomas/kingpin.v2" +) + +type ComponentsOptions struct { + GlobalOptions + Project string +} + +func (jc *JiraCli) CmdComponentsRegistry() *CommandRegistryEntry { + opts := ComponentsOptions{ + GlobalOptions: GlobalOptions{ + Template: "components", + }, + } + + return &CommandRegistryEntry{ + "Show components for a project", + func() error { + return jc.CmdComponents(&opts) + }, + func(cmd *kingpin.CmdClause) error { + return jc.CmdComponentsUsage(cmd, &opts) + }, + } +} + +func (jc *JiraCli) CmdComponentsUsage(cmd *kingpin.CmdClause, opts *ComponentsOptions) error { + if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { + return err + } + jc.TemplateUsage(cmd, &opts.GlobalOptions) + cmd.Flag("project", "project to list components").Short('p').StringVar(&opts.Project) + + return nil +} + +// CmdComponents will get available components for project and send to the "components" template +func (jc *JiraCli) CmdComponents(opts *ComponentsOptions) error { + if opts.Project == "" { + return fmt.Errorf("Project Required.") + } + data, err := jc.GetProjectComponents(opts.Project) + if err != nil { + return err + } + return jc.runTemplate(opts.Template, data, nil) +} diff --git a/jiracli/templates.go b/jiracli/templates.go index f4a7b8ff..b31ad25f 100644 --- a/jiracli/templates.go +++ b/jiracli/templates.go @@ -300,10 +300,10 @@ 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 ""}} +project: {{or .project ""}} +name: {{or .name ""}} +description: {{or .description ""}} +leadUserName: {{or .leadUserName ""}} ` const defaultIssuetypesTemplate = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}} diff --git a/project.go b/project.go new file mode 100644 index 00000000..ab84a57e --- /dev/null +++ b/project.go @@ -0,0 +1,23 @@ +package jira + +import ( + "fmt" + + "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" +) + +// https://docs.atlassian.com/jira/REST/cloud/#api/2/project-getProjectComponents +func (j *Jira) GetProjectComponents(project string) (*jiradata.Components, error) { + uri := fmt.Sprintf("%s/rest/api/2/project/%s/components", j.Endpoint, project) + resp, err := j.UA.GetJSON(uri) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + results := jiradata.Components{} + return &results, readJSON(resp.Body, &results) + } + return nil, responseError(resp) +}