refactor trivial objects in favor of arguments to static functions

This commit is contained in:
Cory Bennett
2017-08-27 00:47:11 -07:00
parent 5716a7cb59
commit 1f345cedee
49 changed files with 840 additions and 629 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ LDFLAGS:=-X jira.VERSION=$(CURVER) -w
ifneq ($(DEBUG),) ifneq ($(DEBUG),)
GOBUILD=go get -v github.com/mailgun/godebug && GOBUILD=go get -v github.com/mailgun/godebug &&
else else
GOBUILD=go build -v -ldflags "$(LDFLAGS) -s" GOBUILD=go build -gcflags="-e -complete" -v -ldflags "$(LDFLAGS) -s"
endif endif
build: build:
+54 -48
View File
@@ -3,8 +3,10 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"runtime/debug" "runtime/debug"
"github.com/coryb/figtree"
"github.com/coryb/oreo" "github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1" jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
@@ -63,205 +65,209 @@ func main() {
return nil return nil
}).Counter() }).Counter()
cli := jiracli.New(".jira.d") fig := figtree.NewFigTree()
fig.EnvPrefix = "JIRA"
fig.ConfigDir = ".jira.d"
o := oreo.New().WithCookieFile(filepath.Join(jiracli.Homedir(), fig.ConfigDir, "cookies.js"))
registry := []jiracli.CommandRegistry{ registry := []jiracli.CommandRegistry{
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "login", Command: "login",
Entry: cli.CmdLoginRegistry(), Entry: jiracli.CmdLoginRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "logout", Command: "logout",
Entry: cli.CmdLogoutRegistry(), Entry: jiracli.CmdLogoutRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "list", Command: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
Entry: cli.CmdListRegistry(), Entry: jiracli.CmdListRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "view", Command: "view",
Entry: cli.CmdViewRegistry(), Entry: jiracli.CmdViewRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "create", Command: "create",
Entry: cli.CmdCreateRegistry(), Entry: jiracli.CmdCreateRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "edit", Command: "edit",
Entry: cli.CmdEditRegistry(), Entry: jiracli.CmdEditRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "comment", Command: "comment",
Entry: cli.CmdCommentRegistry(), Entry: jiracli.CmdCommentRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "worklog list", Command: "worklog list",
Entry: cli.CmdWorklogListRegistry(), Entry: jiracli.CmdWorklogListRegistry(fig, o),
Default: true, Default: true,
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "worklog add", Command: "worklog add",
Entry: cli.CmdWorklogAddRegistry(), Entry: jiracli.CmdWorklogAddRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "fields", Command: "fields",
Entry: cli.CmdFieldsRegistry(), Entry: jiracli.CmdFieldsRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "createmeta", Command: "createmeta",
Entry: cli.CmdCreateMetaRegistry(), Entry: jiracli.CmdCreateMetaRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "editmeta", Command: "editmeta",
Entry: cli.CmdEditMetaRegistry(), Entry: jiracli.CmdEditMetaRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "subtask", Command: "subtask",
Entry: cli.CmdSubtaskRegistry(), Entry: jiracli.CmdSubtaskRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "dup", Command: "dup",
Entry: cli.CmdDupRegistry(), Entry: jiracli.CmdDupRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "block", Command: "block",
Entry: cli.CmdBlockRegistry(), Entry: jiracli.CmdBlockRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "issuelink", Command: "issuelink",
Entry: cli.CmdIssueLinkRegistry(), Entry: jiracli.CmdIssueLinkRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "issuelinktypes", Command: "issuelinktypes",
Entry: cli.CmdIssueLinkTypesRegistry(), Entry: jiracli.CmdIssueLinkTypesRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "transition", Command: "transition",
Aliases: []string{"trans"}, Aliases: []string{"trans"},
Entry: cli.CmdTransitionRegistry(""), Entry: jiracli.CmdTransitionRegistry(fig, o, ""),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "transitions", Command: "transitions",
Entry: cli.CmdTransitionsRegistry("transitions"), Entry: jiracli.CmdTransitionsRegistry(fig, o, "transitions"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "transmeta", Command: "transmeta",
Entry: cli.CmdTransitionsRegistry("debug"), Entry: jiracli.CmdTransitionsRegistry(fig, o, "debug"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "close", Command: "close",
Entry: cli.CmdTransitionRegistry("close"), Entry: jiracli.CmdTransitionRegistry(fig, o, "close"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "acknowledge", Command: "acknowledge",
Aliases: []string{"ack"}, Aliases: []string{"ack"},
Entry: cli.CmdTransitionRegistry("acknowledge"), Entry: jiracli.CmdTransitionRegistry(fig, o, "acknowledge"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "reopen", Command: "reopen",
Entry: cli.CmdTransitionRegistry("reopen"), Entry: jiracli.CmdTransitionRegistry(fig, o, "reopen"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "resolve", Command: "resolve",
Entry: cli.CmdTransitionRegistry("resolve"), Entry: jiracli.CmdTransitionRegistry(fig, o, "resolve"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "start", Command: "start",
Entry: cli.CmdTransitionRegistry("start"), Entry: jiracli.CmdTransitionRegistry(fig, o, "start"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "stop", Command: "stop",
Entry: cli.CmdTransitionRegistry("stop"), Entry: jiracli.CmdTransitionRegistry(fig, o, "stop"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "todo", Command: "todo",
Entry: cli.CmdTransitionRegistry("To Do"), Entry: jiracli.CmdTransitionRegistry(fig, o, "To Do"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "backlog", Command: "backlog",
Entry: cli.CmdTransitionRegistry("Backlog"), Entry: jiracli.CmdTransitionRegistry(fig, o, "Backlog"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "done", Command: "done",
Entry: cli.CmdTransitionRegistry("Done"), Entry: jiracli.CmdTransitionRegistry(fig, o, "Done"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "in-progress", Command: "in-progress",
Aliases: []string{"prog", "progress"}, Aliases: []string{"prog", "progress"},
Entry: cli.CmdTransitionRegistry("Progress"), Entry: jiracli.CmdTransitionRegistry(fig, o, "Progress"),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "vote", Command: "vote",
Entry: cli.CmdVoteRegistry(), Entry: jiracli.CmdVoteRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "rank", Command: "rank",
Entry: cli.CmdRankRegistry(), Entry: jiracli.CmdRankRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "watch", Command: "watch",
Entry: cli.CmdWatchRegistry(), Entry: jiracli.CmdWatchRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "labels add", Command: "labels add",
Entry: cli.CmdLabelsAddRegistry(), Entry: jiracli.CmdLabelsAddRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "labels set", Command: "labels set",
Entry: cli.CmdLabelsAddRegistry(), Entry: jiracli.CmdLabelsAddRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "labels remove", Command: "labels remove",
Entry: cli.CmdLabelsAddRegistry(), Entry: jiracli.CmdLabelsAddRegistry(fig, o),
Aliases: []string{"rm"}, Aliases: []string{"rm"},
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "take", Command: "take",
Entry: cli.CmdTakeRegistry(), Entry: jiracli.CmdTakeRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "assign", Command: "assign",
Entry: cli.CmdAssignRegistry(), Entry: jiracli.CmdAssignRegistry(fig, o),
Aliases: []string{"give"}, Aliases: []string{"give"},
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "unassign", Command: "unassign",
Entry: cli.CmdUnassignRegistry(), Entry: jiracli.CmdUnassignRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "component add", Command: "component add",
Entry: cli.CmdComponentAddRegistry(), Entry: jiracli.CmdComponentAddRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "components", Command: "components",
Entry: cli.CmdComponentsRegistry(), Entry: jiracli.CmdComponentsRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "issuetypes", Command: "issuetypes",
Entry: cli.CmdIssueTypesRegistry(), Entry: jiracli.CmdIssueTypesRegistry(fig, o),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "export-templates", Command: "export-templates",
Entry: cli.CmdExportTemplatesRegistry(), Entry: jiracli.CmdExportTemplatesRegistry(fig),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "unexport-templates", Command: "unexport-templates",
Entry: cli.CmdUnexportTemplatesRegistry(), Entry: jiracli.CmdUnexportTemplatesRegistry(fig),
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "browse", Command: "browse",
Entry: cli.CmdBrowseRegistry(), Entry: jiracli.CmdBrowseRegistry(fig),
Aliases: []string{"b"}, Aliases: []string{"b"},
}, },
jiracli.CommandRegistry{ jiracli.CommandRegistry{
Command: "request", Command: "request",
Entry: cli.CmdRequestRegistry(), Entry: jiracli.CmdRequestRegistry(fig, o),
Aliases: []string{"req"}, Aliases: []string{"req"},
}, },
} }
cli.Register(app, registry) jiracli.Register(app, registry)
app.Terminate(func(status int) { app.Terminate(func(status int) {
for _, arg := range os.Args { for _, arg := range os.Args {
+6 -2
View File
@@ -14,13 +14,17 @@ type ComponentProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/component-createComponent // https://docs.atlassian.com/jira/REST/cloud/#api/2/component-createComponent
func (j *Jira) CreateComponent(cp ComponentProvider) (*jiradata.Component, error) { func (j *Jira) CreateComponent(cp ComponentProvider) (*jiradata.Component, error) {
return CreateComponent(j.UA, j.Endpoint, cp)
}
func CreateComponent(ua HttpClient, endpoint string, cp ComponentProvider) (*jiradata.Component, error) {
req := cp.ProvideComponent() req := cp.ProvideComponent()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/api/2/component", j.Endpoint) uri := fmt.Sprintf("%s/rest/api/2/component", endpoint)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
+6 -2
View File
@@ -8,8 +8,12 @@ import (
// https://docs.atlassian.com/jira/REST/cloud/#api/2/field-getFields // https://docs.atlassian.com/jira/REST/cloud/#api/2/field-getFields
func (j *Jira) GetFields() ([]jiradata.Field, error) { func (j *Jira) GetFields() ([]jiradata.Field, error) {
uri := fmt.Sprintf("%s/rest/api/2/field", j.Endpoint) return GetFields(j.UA, j.Endpoint)
resp, err := j.UA.GetJSON(uri) }
func GetFields(ua HttpClient, endpoint string) ([]jiradata.Field, error) {
uri := fmt.Sprintf("%s/rest/api/2/field", endpoint)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
Generated
+2 -2
View File
@@ -17,9 +17,9 @@ imports:
subpackages: subpackages:
- generic - generic
- name: github.com/coryb/figtree - name: github.com/coryb/figtree
version: 97f630386644abe852de0f4df3befd74bf0a5f9e version: 405935ba249b758f31f4ca2132c4fed7702cc622
- name: github.com/coryb/oreo - name: github.com/coryb/oreo
version: a99f8c323f9746fc5b576349f1ffee4af0bc5ff2 version: b59de1c7ff7fe9e084278487f69a07cb667de9b3
- name: github.com/fatih/camelcase - name: github.com/fatih/camelcase
version: f6a740d52f961c60348ebb109adde9f4635d7540 version: f6a740d52f961c60348ebb109adde9f4635d7540
- name: github.com/guelfey/go.dbus - name: github.com/guelfey/go.dbus
+115 -39
View File
@@ -46,12 +46,16 @@ func (o *IssueOptions) ProvideIssueQueryString() string {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssue // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getIssue
func (j *Jira) GetIssue(issue string, iqg IssueQueryProvider) (*jiradata.Issue, error) { func (j *Jira) GetIssue(issue string, iqg IssueQueryProvider) (*jiradata.Issue, error) {
return GetIssue(j.UA, j.Endpoint, issue, iqg)
}
func GetIssue(ua HttpClient, endpoint string, issue string, iqg IssueQueryProvider) (*jiradata.Issue, error) {
query := "" query := ""
if iqg != nil { if iqg != nil {
query = iqg.ProvideIssueQueryString() query = iqg.ProvideIssueQueryString()
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s%s", j.Endpoint, issue, query) uri := fmt.Sprintf("%s/rest/api/2/issue/%s%s", endpoint, issue, query)
resp, err := j.UA.GetJSON(uri) resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -64,15 +68,19 @@ func (j *Jira) GetIssue(issue string, iqg IssueQueryProvider) (*jiradata.Issue,
return nil, responseError(resp) return nil, responseError(resp)
} }
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/worklog-getIssueWorklog
func (j *Jira) GetIssueWorklog(issue string) (*jiradata.Worklogs, error) { func (j *Jira) GetIssueWorklog(issue string) (*jiradata.Worklogs, error) {
return GetIssueWorklog(j.UA, j.Endpoint, issue)
}
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/worklog-getIssueWorklog
func GetIssueWorklog(ua HttpClient, endpoint string, issue string) (*jiradata.Worklogs, error) {
startAt := 0 startAt := 0
total := 1 total := 1
maxResults := 100 maxResults := 100
worklogs := jiradata.Worklogs{} worklogs := jiradata.Worklogs{}
for startAt < total { for startAt < total {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog?startAt=%d&maxResults=%d", j.Endpoint, issue, startAt, maxResults) uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog?startAt=%d&maxResults=%d", endpoint, issue, startAt, maxResults)
resp, err := j.UA.GetJSON(uri) resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -102,13 +110,17 @@ type WorklogProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/worklog-addWorklog // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/worklog-addWorklog
func (j *Jira) AddIssueWorklog(issue string, wp WorklogProvider) (*jiradata.Worklog, error) { func (j *Jira) AddIssueWorklog(issue string, wp WorklogProvider) (*jiradata.Worklog, error) {
return AddIssueWorklog(j.UA, j.Endpoint, issue, wp)
}
func AddIssueWorklog(ua HttpClient, endpoint string, issue string, wp WorklogProvider) (*jiradata.Worklog, error) {
req := wp.ProvideWorklog() req := wp.ProvideWorklog()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog", j.Endpoint, issue) uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog", endpoint, issue)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -123,8 +135,12 @@ func (j *Jira) AddIssueWorklog(issue string, wp WorklogProvider) (*jiradata.Work
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getEditIssueMeta // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getEditIssueMeta
func (j *Jira) GetIssueEditMeta(issue string) (*jiradata.EditMeta, error) { func (j *Jira) GetIssueEditMeta(issue string) (*jiradata.EditMeta, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/editmeta", j.Endpoint, issue) return GetIssueEditMeta(j.UA, j.Endpoint, issue)
resp, err := j.UA.GetJSON(uri) }
func GetIssueEditMeta(ua HttpClient, endpoint string, issue string) (*jiradata.EditMeta, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/editmeta", endpoint, issue)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -143,13 +159,17 @@ type IssueUpdateProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-editIssue // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-editIssue
func (j *Jira) EditIssue(issue string, iup IssueUpdateProvider) error { func (j *Jira) EditIssue(issue string, iup IssueUpdateProvider) error {
return EditIssue(j.UA, j.Endpoint, issue, iup)
}
func EditIssue(ua HttpClient, endpoint string, issue string, iup IssueUpdateProvider) error {
req := iup.ProvideIssueUpdate() req := iup.ProvideIssueUpdate()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return err return err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s", j.Endpoint, issue) uri := fmt.Sprintf("%s/rest/api/2/issue/%s", endpoint, issue)
resp, err := j.UA.Put(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Put(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return err return err
} }
@@ -163,13 +183,17 @@ func (j *Jira) EditIssue(issue string, iup IssueUpdateProvider) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-createIssue // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-createIssue
func (j *Jira) CreateIssue(iup IssueUpdateProvider) (*jiradata.IssueCreateResponse, error) { func (j *Jira) CreateIssue(iup IssueUpdateProvider) (*jiradata.IssueCreateResponse, error) {
return CreateIssue(j.UA, j.Endpoint, iup)
}
func CreateIssue(ua HttpClient, endpoint string, iup IssueUpdateProvider) (*jiradata.IssueCreateResponse, error) {
req := iup.ProvideIssueUpdate() req := iup.ProvideIssueUpdate()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue", j.Endpoint) uri := fmt.Sprintf("%s/rest/api/2/issue", endpoint)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -184,8 +208,12 @@ func (j *Jira) CreateIssue(iup IssueUpdateProvider) (*jiradata.IssueCreateRespon
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getCreateIssueMeta // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getCreateIssueMeta
func (j *Jira) GetIssueCreateMetaProject(projectKey string) (*jiradata.CreateMetaProject, error) { func (j *Jira) GetIssueCreateMetaProject(projectKey string) (*jiradata.CreateMetaProject, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&expand=projects.issuetypes.fields", j.Endpoint, projectKey) return GetIssueCreateMetaProject(j.UA, j.Endpoint, projectKey)
resp, err := j.UA.GetJSON(uri) }
func GetIssueCreateMetaProject(ua HttpClient, endpoint string, projectKey string) (*jiradata.CreateMetaProject, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&expand=projects.issuetypes.fields", endpoint, projectKey)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -209,8 +237,12 @@ func (j *Jira) GetIssueCreateMetaProject(projectKey string) (*jiradata.CreateMet
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getCreateIssueMeta // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getCreateIssueMeta
func (j *Jira) GetIssueCreateMetaIssueType(projectKey, issueTypeName string) (*jiradata.CreateMetaIssueType, error) { func (j *Jira) GetIssueCreateMetaIssueType(projectKey, issueTypeName string) (*jiradata.CreateMetaIssueType, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&issuetypeNames=%s&expand=projects.issuetypes.fields", j.Endpoint, projectKey, issueTypeName) return GetIssueCreateMetaIssueType(j.UA, j.Endpoint, projectKey, issueTypeName)
resp, err := j.UA.GetJSON(uri) }
func GetIssueCreateMetaIssueType(ua HttpClient, endpoint string, projectKey, issueTypeName string) (*jiradata.CreateMetaIssueType, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&issuetypeNames=%s&expand=projects.issuetypes.fields", endpoint, projectKey, issueTypeName)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -242,13 +274,17 @@ type LinkIssueProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issueLink-linkIssues // https://docs.atlassian.com/jira/REST/cloud/#api/2/issueLink-linkIssues
func (j *Jira) LinkIssues(lip LinkIssueProvider) error { func (j *Jira) LinkIssues(lip LinkIssueProvider) error {
return LinkIssues(j.UA, j.Endpoint, lip)
}
func LinkIssues(ua HttpClient, endpoint string, lip LinkIssueProvider) error {
req := lip.ProvideLinkIssueRequest() req := lip.ProvideLinkIssueRequest()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return err return err
} }
uri := fmt.Sprintf("%s/rest/api/2/issueLink", j.Endpoint) uri := fmt.Sprintf("%s/rest/api/2/issueLink", endpoint)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return err return err
} }
@@ -262,8 +298,12 @@ func (j *Jira) LinkIssues(lip LinkIssueProvider) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getTransitions // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-getTransitions
func (j *Jira) GetIssueTransitions(issue string) (*jiradata.TransitionsMeta, error) { func (j *Jira) GetIssueTransitions(issue string) (*jiradata.TransitionsMeta, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions?expand=transitions.fields", j.Endpoint, issue) return GetIssueTransitions(j.UA, j.Endpoint, issue)
resp, err := j.UA.GetJSON(uri) }
func GetIssueTransitions(ua HttpClient, endpoint string, issue string) (*jiradata.TransitionsMeta, error) {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions?expand=transitions.fields", endpoint, issue)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -278,13 +318,17 @@ func (j *Jira) GetIssueTransitions(issue string) (*jiradata.TransitionsMeta, err
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-doTransition // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-doTransition
func (j *Jira) TransitionIssue(issue string, iup IssueUpdateProvider) error { func (j *Jira) TransitionIssue(issue string, iup IssueUpdateProvider) error {
return TransitionIssue(j.UA, j.Endpoint, issue, iup)
}
func TransitionIssue(ua HttpClient, endpoint string, issue string, iup IssueUpdateProvider) error {
req := iup.ProvideIssueUpdate() req := iup.ProvideIssueUpdate()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return err return err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions", j.Endpoint, issue) uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions", endpoint, issue)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return err return err
} }
@@ -298,8 +342,12 @@ func (j *Jira) TransitionIssue(issue string, iup IssueUpdateProvider) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issueLinkType-getIssueLinkTypes // https://docs.atlassian.com/jira/REST/cloud/#api/2/issueLinkType-getIssueLinkTypes
func (j *Jira) GetIssueLinkTypes() (*jiradata.IssueLinkTypes, error) { func (j *Jira) GetIssueLinkTypes() (*jiradata.IssueLinkTypes, error) {
uri := fmt.Sprintf("%s/rest/api/2/issueLinkType", j.Endpoint) return GetIssueLinkTypes(j.UA, j.Endpoint)
resp, err := j.UA.GetJSON(uri) }
func GetIssueLinkTypes(ua HttpClient, endpoint string) (*jiradata.IssueLinkTypes, error) {
uri := fmt.Sprintf("%s/rest/api/2/issueLinkType", endpoint)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -318,8 +366,12 @@ func (j *Jira) GetIssueLinkTypes() (*jiradata.IssueLinkTypes, error) {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addVote // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addVote
func (j *Jira) IssueAddVote(issue string) error { func (j *Jira) IssueAddVote(issue string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/votes", j.Endpoint, issue) return IssueAddVote(j.UA, j.Endpoint, issue)
resp, err := j.UA.Post(uri, "application/json", strings.NewReader("{}")) }
func IssueAddVote(ua HttpClient, endpoint string, issue string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/votes", endpoint, issue)
resp, err := ua.Post(uri, "application/json", strings.NewReader("{}"))
if err != nil { if err != nil {
return err return err
} }
@@ -333,8 +385,12 @@ func (j *Jira) IssueAddVote(issue string) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-removeVote // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-removeVote
func (j *Jira) IssueRemoveVote(issue string) error { func (j *Jira) IssueRemoveVote(issue string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/votes", j.Endpoint, issue) return IssueRemoveVote(j.UA, j.Endpoint, issue)
resp, err := j.UA.Delete(uri) }
func IssueRemoveVote(ua HttpClient, endpoint string, issue string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/votes", endpoint, issue)
resp, err := ua.Delete(uri)
if err != nil { if err != nil {
return err return err
} }
@@ -352,13 +408,17 @@ type RankRequestProvider interface {
// https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/issue-rankIssues // https://docs.atlassian.com/jira-software/REST/cloud/#agile/1.0/issue-rankIssues
func (j *Jira) RankIssues(rrp RankRequestProvider) error { func (j *Jira) RankIssues(rrp RankRequestProvider) error {
return RankIssues(j.UA, j.Endpoint, rrp)
}
func RankIssues(ua HttpClient, endpoint string, rrp RankRequestProvider) error {
req := rrp.ProvideRankRequest() req := rrp.ProvideRankRequest()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return err return err
} }
uri := fmt.Sprintf("%s/rest/agile/1.0/issue/rank", j.Endpoint) uri := fmt.Sprintf("%s/rest/agile/1.0/issue/rank", endpoint)
resp, err := j.UA.Put(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Put(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return err return err
} }
@@ -372,8 +432,12 @@ func (j *Jira) RankIssues(rrp RankRequestProvider) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addWatcher // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addWatcher
func (j *Jira) IssueAddWatcher(issue, user string) error { func (j *Jira) IssueAddWatcher(issue, user string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/watchers", j.Endpoint, issue) return IssueAddWatcher(j.UA, j.Endpoint, issue, user)
resp, err := j.UA.Post(uri, "application/json", strings.NewReader(fmt.Sprintf("%q", user))) }
func IssueAddWatcher(ua HttpClient, endpoint string, issue, user string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/watchers", endpoint, issue)
resp, err := ua.Post(uri, "application/json", strings.NewReader(fmt.Sprintf("%q", user)))
if err != nil { if err != nil {
return err return err
} }
@@ -387,8 +451,12 @@ func (j *Jira) IssueAddWatcher(issue, user string) error {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addWatcher // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-addWatcher
func (j *Jira) IssueRemoveWatcher(issue, user string) error { func (j *Jira) IssueRemoveWatcher(issue, user string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/watchers?username=%s", j.Endpoint, issue, user) return IssueRemoveWatcher(j.UA, j.Endpoint, issue, user)
resp, err := j.UA.Delete(uri) }
func IssueRemoveWatcher(ua HttpClient, endpoint string, issue, user string) error {
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/watchers?username=%s", endpoint, issue, user)
resp, err := ua.Delete(uri)
if err != nil { if err != nil {
return err return err
} }
@@ -406,13 +474,17 @@ type CommentProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/comment-addComment // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/comment-addComment
func (j *Jira) IssueAddComment(issue string, cp CommentProvider) (*jiradata.Comment, error) { func (j *Jira) IssueAddComment(issue string, cp CommentProvider) (*jiradata.Comment, error) {
return IssueAddComment(j.UA, j.Endpoint, issue, cp)
}
func IssueAddComment(ua HttpClient, endpoint string, issue string, cp CommentProvider) (*jiradata.Comment, error) {
req := cp.ProvideComment() req := cp.ProvideComment()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/comment", j.Endpoint, issue) uri := fmt.Sprintf("%s/rest/api/2/issue/%s/comment", endpoint, issue)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -431,6 +503,10 @@ type UserProvider interface {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-assign // https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-assign
func (j *Jira) IssueAssign(issue, name string) error { func (j *Jira) IssueAssign(issue, name string) error {
return IssueAssign(j.UA, j.Endpoint, issue, name)
}
func IssueAssign(ua HttpClient, endpoint string, issue, name string) error {
// this is special, not using the jiradata.User structure // this is special, not using the jiradata.User structure
// because we need to be able to send `null` as the name param // because we need to be able to send `null` as the name param
// when we want to un-assign the issue // when we want to un-assign the issue
@@ -445,8 +521,8 @@ func (j *Jira) IssueAssign(issue, name string) error {
if err != nil { if err != nil {
return err return err
} }
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/assignee", j.Endpoint, issue) uri := fmt.Sprintf("%s/rest/api/2/issue/%s/assignee", endpoint, issue)
resp, err := j.UA.Put(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Put(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return err return err
} }
+18 -13
View File
@@ -3,34 +3,39 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type AssignOptions struct { type AssignOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Assignee string Assignee string
} }
func (jc *JiraCli) CmdAssignRegistry() *CommandRegistryEntry { func CmdAssignRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := AssignOptions{} opts := AssignOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Assign user to issue", "Assign user to issue",
func() error { func() error {
return jc.CmdAssign(&opts) return CmdAssign(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdAssignUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdAssignUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdAssignUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error { func CmdAssignUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Flag("default", "use default user for assignee").PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("default", "use default user for assignee").PreAction(func(ctx *kingpin.ParseContext) error {
if flagValue(ctx, "default") == "true" { if flagValue(ctx, "default") == "true" {
opts.Assignee = "-1" opts.Assignee = "-1"
@@ -43,16 +48,16 @@ func (jc *JiraCli) CmdAssignUsage(cmd *kingpin.CmdClause, opts *AssignOptions) e
} }
// CmdAssign will assign an issue to a user // CmdAssign will assign an issue to a user
func (jc *JiraCli) CmdAssign(opts *AssignOptions) error { func CmdAssign(o *oreo.Client, opts *AssignOptions) error {
err := jc.IssueAssign(opts.Issue, opts.Assignee) err := jira.IssueAssign(o, opts.Endpoint.Value, opts.Issue, opts.Assignee)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
+21 -18
View File
@@ -4,19 +4,21 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type BlockOptions struct { type BlockOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.LinkIssueRequest jiradata.LinkIssueRequest `yaml:",inline" figtree:",inline"`
Blocker string Blocker string
Issue string Issue string
} }
func (jc *JiraCli) CmdBlockRegistry() *CommandRegistryEntry { func CmdBlockRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := BlockOptions{ opts := BlockOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("edit"), Template: figtree.NewStringOption("edit"),
@@ -33,21 +35,22 @@ func (jc *JiraCli) CmdBlockRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Mark issues as blocker", "Mark issues as blocker",
func() error { func() error {
return jc.CmdBlock(&opts) return CmdBlock(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdBlockUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdBlockUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdBlockUsage(cmd *kingpin.CmdClause, opts *BlockOptions) error { func CmdBlockUsage(cmd *kingpin.CmdClause, opts *BlockOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("comment", "Comment message when marking issue as blocker").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message when marking issue as blocker").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Comment = &jiradata.Comment{ opts.Comment = &jiradata.Comment{
Body: flagValue(ctx, "comment"), Body: flagValue(ctx, "comment"),
@@ -61,17 +64,17 @@ func (jc *JiraCli) CmdBlockUsage(cmd *kingpin.CmdClause, opts *BlockOptions) err
// CmdBlock will update the given issue as being a duplicate by the given dup issue // CmdBlock will update the given issue as being a duplicate by the given dup issue
// and will attempt to resolve the dup issue // and will attempt to resolve the dup issue
func (jc *JiraCli) CmdBlock(opts *BlockOptions) error { func CmdBlock(o *oreo.Client, opts *BlockOptions) error {
if err := jc.LinkIssues(&opts.LinkIssueRequest); err != nil { if err := jira.LinkIssues(o, opts.Endpoint.Value, &opts.LinkIssueRequest); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
fmt.Printf("OK %s %s/browse/%s\n", opts.Blocker, jc.Endpoint, opts.Blocker) fmt.Printf("OK %s %s/browse/%s\n", opts.Blocker, opts.Endpoint.Value, opts.Blocker)
if opts.Browse.Value { if opts.Browse.Value {
if err := jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}); err != nil { if err := CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}); err != nil {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Blocker}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Blocker})
} }
} }
+11 -9
View File
@@ -3,31 +3,33 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/pkg/browser" "github.com/pkg/browser"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type BrowseOptions struct { type BrowseOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdBrowseRegistry() *CommandRegistryEntry { func CmdBrowseRegistry(fig *figtree.FigTree) *CommandRegistryEntry {
opts := BrowseOptions{} opts := BrowseOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Open issue in browser", "Open issue in browser",
func() error { func() error {
return jc.CmdBrowse(&opts) return CmdBrowse(&opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdBrowseUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdBrowseUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdBrowseUsage(cmd *kingpin.CmdClause, opts *BrowseOptions) error { func CmdBrowseUsage(cmd *kingpin.CmdClause, opts *BrowseOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
cmd.Arg("ISSUE", "Issue to browse to").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "Issue to browse to").Required().StringVar(&opts.Issue)
@@ -36,6 +38,6 @@ func (jc *JiraCli) CmdBrowseUsage(cmd *kingpin.CmdClause, opts *BrowseOptions) e
} }
// CmdBrowse open the default system browser to the provided issue // CmdBrowse open the default system browser to the provided issue
func (jc *JiraCli) CmdBrowse(opts *BrowseOptions) error { func CmdBrowse(opts *BrowseOptions) error {
return browser.OpenURL(fmt.Sprintf("%s/browse/%s", jc.Endpoint, opts.Issue)) return browser.OpenURL(fmt.Sprintf("%s/browse/%s", opts.Endpoint.Value, opts.Issue))
} }
+29 -43
View File
@@ -7,17 +7,13 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath"
"reflect" "reflect"
"strings" "strings"
"github.com/AlecAivazis/survey" "github.com/AlecAivazis/survey"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
shellquote "github.com/kballard/go-shellquote" shellquote "github.com/kballard/go-shellquote"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
yaml "gopkg.in/coryb/yaml.v2" yaml "gopkg.in/coryb/yaml.v2"
logging "gopkg.in/op/go-logging.v1" logging "gopkg.in/op/go-logging.v1"
@@ -25,11 +21,11 @@ import (
var log = logging.MustGetLogger("jira") var log = logging.MustGetLogger("jira")
type JiraCli struct { // type JiraCli struct {
jira.Jira `yaml:",inline"` // jira.Jira `yaml:",inline"`
ConfigDir string // ConfigDir string
oreoAgent *oreo.Client // oreoAgent *oreo.Client
} // }
type Exit struct { type Exit struct {
Code int Code int
@@ -38,10 +34,11 @@ type Exit struct {
type GlobalOptions struct { type GlobalOptions struct {
Browse figtree.BoolOption `json:"browse,omitempty" yaml:"browse,omitempty"` Browse figtree.BoolOption `json:"browse,omitempty" yaml:"browse,omitempty"`
Editor figtree.StringOption `json:"editor,omitempty" yaml:"editor,omitempty"` Editor figtree.StringOption `json:"editor,omitempty" yaml:"editor,omitempty"`
Endpoint figtree.StringOption `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
SkipEditing figtree.BoolOption `json:"noedit,omitempty" yaml:"noedit,omitempty"` SkipEditing figtree.BoolOption `json:"noedit,omitempty" yaml:"noedit,omitempty"`
PasswordSource figtree.StringOption `json:"password-source,omitempty" yaml:"password-source,omitempty"` PasswordSource figtree.StringOption `json:"password-source,omitempty" yaml:"password-source,omitempty"`
Template figtree.StringOption `json:"template,omitempty" yaml:"template,omitempty"` Template figtree.StringOption `json:"template,omitempty" yaml:"template,omitempty"`
User figtree.StringOption `json:"user,omitempty", yaml:"user,omitempty"` User figtree.StringOption `json:"user,omitempty" yaml:"user,omitempty"`
} }
type CommandRegistryEntry struct { type CommandRegistryEntry struct {
@@ -63,18 +60,18 @@ type kingpinAppOrCommand interface {
GetCommand(string) *kingpin.CmdClause GetCommand(string) *kingpin.CmdClause
} }
func New(configDir string) *JiraCli { // func New(configDir string) *JiraCli {
agent := oreo.New().WithCookieFile(filepath.Join(homedir(), configDir, "cookies.js")) // agent := oreo.New().WithCookieFile(filepath.Join(homedir(), configDir, "cookies.js"))
return &JiraCli{ // return &JiraCli{
ConfigDir: configDir, // ConfigDir: configDir,
Jira: jira.Jira{ // Jira: jira.Jira{
UA: agent, // UA: agent,
}, // },
oreoAgent: agent, // oreoAgent: agent,
} // }
} // }
func (jc *JiraCli) Register(app *kingpin.Application, reg []CommandRegistry) { func Register(app *kingpin.Application, reg []CommandRegistry) {
for _, command := range reg { for _, command := range reg {
copy := command copy := command
commandFields := strings.Fields(copy.Command) commandFields := strings.Fields(copy.Command)
@@ -108,50 +105,39 @@ func (jc *JiraCli) Register(app *kingpin.Application, reg []CommandRegistry) {
} }
} }
func (jc *JiraCli) GlobalUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) error { func GlobalUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) error {
jc.LoadConfigs(cmd, opts)
cmd.PreAction(func(_ *kingpin.ParseContext) error { cmd.PreAction(func(_ *kingpin.ParseContext) error {
os.Setenv("JIRA_OPERATION", cmd.FullCommand())
fig := figtree.NewFigTree()
fig.EnvPrefix = "JIRA"
// populate JiraCli fields if defined in configs (ie for Endpoint)
if err := fig.LoadAllConfigs(path.Join(jc.ConfigDir, "config.yml"), jc); err != nil {
return err
}
if opts.User.Value == "" { if opts.User.Value == "" {
opts.User = figtree.NewStringOption(os.Getenv("USER")) opts.User = figtree.NewStringOption(os.Getenv("USER"))
} }
return nil return nil
}) })
cmd.Flag("endpoint", "URI to use for Jira").Short('e').StringVar(&jc.Endpoint) cmd.Flag("endpoint", "Base URI to use for Jira").Short('e').SetValue(&opts.Endpoint)
cmd.Flag("user", "Login mame used for authentication with Jira service").Short('u').SetValue(&opts.User) cmd.Flag("user", "Login name used for authentication with Jira service").Short('u').SetValue(&opts.User)
return nil return nil
} }
func (jc *JiraCli) LoadConfigs(cmd *kingpin.CmdClause, opts interface{}) { func LoadConfigs(cmd *kingpin.CmdClause, fig *figtree.FigTree, opts interface{}) {
cmd.PreAction(func(_ *kingpin.ParseContext) error { cmd.PreAction(func(_ *kingpin.ParseContext) error {
os.Setenv("JIRA_OPERATION", cmd.FullCommand()) os.Setenv("JIRA_OPERATION", cmd.FullCommand())
fig := figtree.NewFigTree()
fig.EnvPrefix = "JIRA"
fig.Defaults = opts
// load command specific configs first // load command specific configs first
if err := fig.LoadAllConfigs(path.Join(jc.ConfigDir, strings.Join(strings.Fields(cmd.FullCommand()), "_")+".yml"), opts); err != nil { if err := fig.LoadAllConfigs(strings.Join(strings.Fields(cmd.FullCommand()), "_")+".yml", opts); err != nil {
return err return err
} }
// then load generic configs if not already populated above // then load generic configs if not already populated above
return fig.LoadAllConfigs(path.Join(jc.ConfigDir, "config.yml"), opts) return fig.LoadAllConfigs("config.yml", opts)
}) })
} }
func (jc *JiraCli) BrowseUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) { func BrowseUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) {
cmd.Flag("browse", "Open issue(s) in browser after operation").Short('b').SetValue(&opts.Browse) cmd.Flag("browse", "Open issue(s) in browser after operation").Short('b').SetValue(&opts.Browse)
} }
func (jc *JiraCli) EditorUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) { func EditorUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) {
cmd.Flag("editor", "Editor to use").SetValue(&opts.Editor) cmd.Flag("editor", "Editor to use").SetValue(&opts.Editor)
} }
func (jc *JiraCli) TemplateUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) { func TemplateUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) {
cmd.Flag("template", "Template to use for output").Short('t').SetValue(&opts.Template) cmd.Flag("template", "Template to use for output").Short('t').SetValue(&opts.Template)
} }
@@ -218,8 +204,8 @@ func (o *GlobalOptions) editFile(fileName string) (changes bool, err error) {
return false, err return false, err
} }
func (jc *JiraCli) editLoop(opts *GlobalOptions, input interface{}, output interface{}, submit func() error) error { func editLoop(opts *GlobalOptions, input interface{}, output interface{}, submit func() error) error {
tmpFile, err := jc.tmpTemplate(opts.Template.Value, input) tmpFile, err := tmpTemplate(opts.Template.Value, input)
if err != nil { if err != nil {
return err return err
} }
+19 -16
View File
@@ -4,18 +4,20 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type CommentOptions struct { type CommentOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Overrides map[string]string Overrides map[string]string
Issue string Issue string
} }
func (jc *JiraCli) CmdCommentRegistry() *CommandRegistryEntry { func CmdCommentRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := CommentOptions{ opts := CommentOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("comment"), Template: figtree.NewStringOption("comment"),
@@ -26,21 +28,22 @@ func (jc *JiraCli) CmdCommentRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Add comment to issue", "Add comment to issue",
func() error { func() error {
return jc.CmdComment(&opts) return CmdComment(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdCommentUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdCommentUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdCommentUsage(cmd *kingpin.CmdClause, opts *CommentOptions) error { func CmdCommentUsage(cmd *kingpin.CmdClause, opts *CommentOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Overrides["comment"] = flagValue(ctx, "comment") opts.Overrides["comment"] = flagValue(ctx, "comment")
return nil return nil
@@ -50,25 +53,25 @@ func (jc *JiraCli) CmdCommentUsage(cmd *kingpin.CmdClause, opts *CommentOptions)
} }
// CmdComment will update issue with comment // CmdComment will update issue with comment
func (jc *JiraCli) CmdComment(opts *CommentOptions) error { func CmdComment(o *oreo.Client, opts *CommentOptions) error {
comment := jiradata.Comment{} comment := jiradata.Comment{}
input := struct { input := struct {
Overrides map[string]string Overrides map[string]string
}{ }{
opts.Overrides, opts.Overrides,
} }
err := jc.editLoop(&opts.GlobalOptions, &input, &comment, func() error { err := editLoop(&opts.GlobalOptions, &input, &comment, func() error {
_, err := jc.IssueAddComment(opts.Issue, &comment) _, err := jira.IssueAddComment(o, opts.Endpoint.Value, opts.Issue, &comment)
return err return err
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
+15 -12
View File
@@ -4,17 +4,19 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type ComponentAddOptions struct { type ComponentAddOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.Component jiradata.Component `yaml:",inline" figtree:",inline"`
} }
func (jc *JiraCli) CmdComponentAddRegistry() *CommandRegistryEntry { func CmdComponentAddRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := ComponentAddOptions{ opts := ComponentAddOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("component-add"), Template: figtree.NewStringOption("component-add"),
@@ -24,20 +26,21 @@ func (jc *JiraCli) CmdComponentAddRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Add component", "Add component",
func() error { func() error {
return jc.CmdComponentAdd(&opts) return CmdComponentAdd(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdComponentAddUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdComponentAddUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdComponentAddUsage(cmd *kingpin.CmdClause, opts *ComponentAddOptions) error { func CmdComponentAddUsage(cmd *kingpin.CmdClause, opts *ComponentAddOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing) cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
cmd.Flag("project", "project to create component in").Short('p').StringVar(&opts.Project) 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("name", "name of component").Short('n').StringVar(&opts.Name)
@@ -48,12 +51,12 @@ func (jc *JiraCli) CmdComponentAddUsage(cmd *kingpin.CmdClause, opts *ComponentA
// CmdComponentAdd sends the provided overrides to the "component-add" template for editing, then // 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. // will parse the edited document as YAML and submit the document to jira.
func (jc *JiraCli) CmdComponentAdd(opts *ComponentAddOptions) error { func CmdComponentAdd(o *oreo.Client, opts *ComponentAddOptions) error {
var err error var err error
component := &jiradata.Component{} component := &jiradata.Component{}
var resp *jiradata.Component var resp *jiradata.Component
err = jc.editLoop(&opts.GlobalOptions, &opts.Component, component, func() error { err = editLoop(&opts.GlobalOptions, &opts.Component, component, func() error {
resp, err = jc.CreateComponent(component) resp, err = jira.CreateComponent(o, opts.Endpoint.Value, component)
return err return err
}) })
if err != nil { if err != nil {
+14 -11
View File
@@ -4,16 +4,18 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type ComponentsOptions struct { type ComponentsOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Project string Project string
} }
func (jc *JiraCli) CmdComponentsRegistry() *CommandRegistryEntry { func CmdComponentsRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := ComponentsOptions{ opts := ComponentsOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("components"), Template: figtree.NewStringOption("components"),
@@ -23,32 +25,33 @@ func (jc *JiraCli) CmdComponentsRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Show components for a project", "Show components for a project",
func() error { func() error {
return jc.CmdComponents(&opts) return CmdComponents(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdComponentsUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdComponentsUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdComponentsUsage(cmd *kingpin.CmdClause, opts *ComponentsOptions) error { func CmdComponentsUsage(cmd *kingpin.CmdClause, opts *ComponentsOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("project", "project to list components").Short('p').StringVar(&opts.Project) cmd.Flag("project", "project to list components").Short('p').StringVar(&opts.Project)
return nil return nil
} }
// CmdComponents will get available components for project and send to the "components" template // CmdComponents will get available components for project and send to the "components" template
func (jc *JiraCli) CmdComponents(opts *ComponentsOptions) error { func CmdComponents(o *oreo.Client, opts *ComponentsOptions) error {
if opts.Project == "" { if opts.Project == "" {
return fmt.Errorf("Project Required.") return fmt.Errorf("Project Required.")
} }
data, err := jc.GetProjectComponents(opts.Project) data, err := jira.GetProjectComponents(o, opts.Endpoint.Value, opts.Project)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, data, nil) return runTemplate(opts.Template.Value, data, nil)
} }
+25 -22
View File
@@ -4,20 +4,22 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type CreateOptions struct { type CreateOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.IssueUpdate jiradata.IssueUpdate `yaml:",inline" figtree:",inline"`
Project string Project string
IssueType string IssueType string
Overrides map[string]string Overrides map[string]string
} }
func (jc *JiraCli) CmdCreateRegistry() *CommandRegistryEntry { func CmdCreateRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := CreateOptions{ opts := CreateOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("create"), Template: figtree.NewStringOption("create"),
@@ -28,21 +30,22 @@ func (jc *JiraCli) CmdCreateRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Create issue", "Create issue",
func() error { func() error {
return jc.CmdCreate(&opts) return CmdCreate(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdCreateUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdCreateUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdCreateUsage(cmd *kingpin.CmdClause, opts *CreateOptions) error { func CmdCreateUsage(cmd *kingpin.CmdClause, opts *CreateOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing) cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
cmd.Flag("project", "project to create issue in").Short('p').StringVar(&opts.Project) cmd.Flag("project", "project to create issue in").Short('p').StringVar(&opts.Project)
cmd.Flag("issuetype", "issuetype in to create").Short('i').StringVar(&opts.IssueType) cmd.Flag("issuetype", "issuetype in to create").Short('i').StringVar(&opts.IssueType)
@@ -56,16 +59,16 @@ func (jc *JiraCli) CmdCreateUsage(cmd *kingpin.CmdClause, opts *CreateOptions) e
// CmdCreate sends the create-metadata to the "create" template for editing, then // CmdCreate sends the create-metadata to the "create" template for editing, then
// will parse the edited document as YAML and submit the document to jira. // will parse the edited document as YAML and submit the document to jira.
func (jc *JiraCli) CmdCreate(opts *CreateOptions) error { func CmdCreate(o *oreo.Client, opts *CreateOptions) error {
type templateInput struct { type templateInput struct {
Meta *jiradata.CreateMetaIssueType `yaml:"meta" json:"meta"` Meta *jiradata.CreateMetaIssueType `yaml:"meta" json:"meta"`
Overrides map[string]string `yaml:"overrides" json:"overrides"` Overrides map[string]string `yaml:"overrides" json:"overrides"`
} }
if err := jc.defaultIssueType(&opts.Project, &opts.IssueType); err != nil { if err := defaultIssueType(o, opts.Endpoint.Value, &opts.Project, &opts.IssueType); err != nil {
return err return err
} }
createMeta, err := jc.GetIssueCreateMetaIssueType(opts.Project, opts.IssueType) createMeta, err := jira.GetIssueCreateMetaIssueType(o, opts.Endpoint.Value, opts.Project, opts.IssueType)
if err != nil { if err != nil {
return err return err
} }
@@ -80,30 +83,30 @@ func (jc *JiraCli) CmdCreate(opts *CreateOptions) error {
input.Overrides["user"] = opts.User.Value input.Overrides["user"] = opts.User.Value
var issueResp *jiradata.IssueCreateResponse var issueResp *jiradata.IssueCreateResponse
err = jc.editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error { err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
issueResp, err = jc.CreateIssue(&issueUpdate) issueResp, err = jira.CreateIssue(o, opts.Endpoint.Value, &issueUpdate)
return err return err
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", issueResp.Key, jc.Endpoint, issueResp.Key) fmt.Printf("OK %s %s/browse/%s\n", issueResp.Key, opts.Endpoint.Value, issueResp.Key)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueResp.Key}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueResp.Key})
} }
return nil return nil
} }
func (jc *JiraCli) defaultIssueType(project, issuetype *string) error { func defaultIssueType(o *oreo.Client, endpoint string, project, issuetype *string) error {
if project == nil || *project == "" { if project == nil || *project == "" {
return fmt.Errorf("Project undefined, please use --project argument or set the `project` config property") return fmt.Errorf("Project undefined, please use --project argument or set the `project` config property")
} }
if issuetype != nil && *issuetype != "" { if issuetype != nil && *issuetype != "" {
return nil return nil
} }
projectMeta, err := jc.GetIssueCreateMetaProject(*project) projectMeta, err := jira.GetIssueCreateMetaProject(o, endpoint, *project)
if err != nil { if err != nil {
return err return err
} }
+16 -13
View File
@@ -2,16 +2,18 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type CreateMetaOptions struct { type CreateMetaOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Project string `yaml:"project,omitempty" json:"project,omitempty"` Project string `yaml:"project,omitempty" json:"project,omitempty"`
IssueType string `yaml:"issuetype,omitempty" json:"issuetype,omitempty"` IssueType string `yaml:"issuetype,omitempty" json:"issuetype,omitempty"`
} }
func (jc *JiraCli) CmdCreateMetaRegistry() *CommandRegistryEntry { func CmdCreateMetaRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := CreateMetaOptions{ opts := CreateMetaOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("createmeta"), Template: figtree.NewStringOption("createmeta"),
@@ -21,32 +23,33 @@ func (jc *JiraCli) CmdCreateMetaRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"View 'create' metadata", "View 'create' metadata",
func() error { func() error {
return jc.CmdCreateMeta(&opts) return CmdCreateMeta(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdCreateMetaUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdCreateMetaUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdCreateMetaUsage(cmd *kingpin.CmdClause, opts *CreateMetaOptions) error { func CmdCreateMetaUsage(cmd *kingpin.CmdClause, opts *CreateMetaOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("project", "project to fetch create metadata").Short('p').StringVar(&opts.Project) cmd.Flag("project", "project to fetch create metadata").Short('p').StringVar(&opts.Project)
cmd.Flag("issuetype", "issuetype in project to fetch create metadata").Short('i').StringVar(&opts.IssueType) cmd.Flag("issuetype", "issuetype in project to fetch create metadata").Short('i').StringVar(&opts.IssueType)
return nil return nil
} }
// Create will get issue create metadata and send to "createmeta" template // Create will get issue create metadata and send to "createmeta" template
func (jc *JiraCli) CmdCreateMeta(opts *CreateMetaOptions) error { func CmdCreateMeta(o *oreo.Client, opts *CreateMetaOptions) error {
if err := jc.defaultIssueType(&opts.Project, &opts.IssueType); err != nil { if err := defaultIssueType(o, opts.Endpoint.Value, &opts.Project, &opts.IssueType); err != nil {
return err return err
} }
createMeta, err := jc.GetIssueCreateMetaIssueType(opts.Project, opts.IssueType) createMeta, err := jira.GetIssueCreateMetaIssueType(o, opts.Endpoint.Value, opts.Project, opts.IssueType)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, createMeta, nil) return runTemplate(opts.Template.Value, createMeta, nil)
} }
+24 -21
View File
@@ -4,19 +4,21 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type DupOptions struct { type DupOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.LinkIssueRequest jiradata.LinkIssueRequest `yaml:",inline" figtree:",inline"`
Duplicate string Duplicate string
Issue string Issue string
} }
func (jc *JiraCli) CmdDupRegistry() *CommandRegistryEntry { func CmdDupRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := DupOptions{ opts := DupOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("edit"), Template: figtree.NewStringOption("edit"),
@@ -33,21 +35,22 @@ func (jc *JiraCli) CmdDupRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Mark issues as duplicate", "Mark issues as duplicate",
func() error { func() error {
return jc.CmdDup(&opts) return CmdDup(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdDupUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdDupUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdDupUsage(cmd *kingpin.CmdClause, opts *DupOptions) error { func CmdDupUsage(cmd *kingpin.CmdClause, opts *DupOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("comment", "Comment message when marking issue as duplicate").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message when marking issue as duplicate").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Comment = &jiradata.Comment{ opts.Comment = &jiradata.Comment{
Body: flagValue(ctx, "comment"), Body: flagValue(ctx, "comment"),
@@ -61,13 +64,13 @@ func (jc *JiraCli) CmdDupUsage(cmd *kingpin.CmdClause, opts *DupOptions) error {
// CmdDups will update the given issue as being a duplicate by the given dup issue // CmdDups will update the given issue as being a duplicate by the given dup issue
// and will attempt to resolve the dup issue // and will attempt to resolve the dup issue
func (jc *JiraCli) CmdDup(opts *DupOptions) error { func CmdDup(o *oreo.Client, opts *DupOptions) error {
if err := jc.LinkIssues(&opts.LinkIssueRequest); err != nil { if err := jira.LinkIssues(o, opts.Endpoint.Value, &opts.LinkIssueRequest); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, jc.Endpoint, opts.OutwardIssue.Key) fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, opts.Endpoint.Value, opts.OutwardIssue.Key)
meta, err := jc.GetIssueTransitions(opts.InwardIssue.Key) meta, err := jira.GetIssueTransitions(o, opts.Endpoint.Value, opts.InwardIssue.Key)
if err != nil { if err != nil {
return err return err
} }
@@ -77,7 +80,7 @@ func (jc *JiraCli) CmdDup(opts *DupOptions) error {
issueUpdate := jiradata.IssueUpdate{ issueUpdate := jiradata.IssueUpdate{
Transition: transMeta, Transition: transMeta,
} }
if err = jc.TransitionIssue(opts.InwardIssue.Key, &issueUpdate); err != nil { if err = jira.TransitionIssue(o, opts.Endpoint.Value, opts.InwardIssue.Key, &issueUpdate); err != nil {
return err return err
} }
// if we just started the issue now we need to stop it // if we just started the issue now we need to stop it
@@ -87,12 +90,12 @@ func (jc *JiraCli) CmdDup(opts *DupOptions) error {
} }
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, jc.Endpoint, opts.OutwardIssue.Key) fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, opts.Endpoint.Value, opts.OutwardIssue.Key)
fmt.Printf("OK %s %s/browse/%s\n", opts.InwardIssue.Key, jc.Endpoint, opts.InwardIssue.Key) fmt.Printf("OK %s %s/browse/%s\n", opts.InwardIssue.Key, opts.Endpoint.Value, opts.InwardIssue.Key)
if opts.Browse.Value { if opts.Browse.Value {
if err := jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.OutwardIssue.Key}); err != nil { if err := CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.OutwardIssue.Key}); err != nil {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.InwardIssue.Key}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.InwardIssue.Key})
} }
} }
+28 -26
View File
@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1" jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
@@ -11,14 +12,14 @@ import (
) )
type EditOptions struct { type EditOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.IssueUpdate jiradata.IssueUpdate `yaml:",inline" figtree:",inline"`
jira.SearchOptions jira.SearchOptions `yaml:",inline" figtree:",inline"`
Overrides map[string]string Overrides map[string]string
Issue string Issue string
} }
func (jc *JiraCli) CmdEditRegistry() *CommandRegistryEntry { func CmdEditRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := EditOptions{ opts := EditOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("edit"), Template: figtree.NewStringOption("edit"),
@@ -29,21 +30,22 @@ func (jc *JiraCli) CmdEditRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Edit issue details", "Edit issue details",
func() error { func() error {
return jc.CmdEdit(&opts) return CmdEdit(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdEditUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdEditUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdEditUsage(cmd *kingpin.CmdClause, opts *EditOptions) error { func CmdEditUsage(cmd *kingpin.CmdClause, opts *EditOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing) cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
cmd.Flag("query", "Jira Query Language (JQL) expression for the search to edit multiple issues").Short('q').StringVar(&opts.Query) cmd.Flag("query", "Jira Query Language (JQL) expression for the search to edit multiple issues").Short('q').StringVar(&opts.Query)
cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
@@ -56,18 +58,18 @@ func (jc *JiraCli) CmdEditUsage(cmd *kingpin.CmdClause, opts *EditOptions) error
} }
// Edit will get issue data and send to "edit" template // Edit will get issue data and send to "edit" template
func (jc *JiraCli) CmdEdit(opts *EditOptions) error { func CmdEdit(o *oreo.Client, opts *EditOptions) error {
type templateInput struct { type templateInput struct {
*jiradata.Issue `yaml:",inline"` *jiradata.Issue `yaml:",inline"`
Meta *jiradata.EditMeta `yaml:"meta" json:"meta"` Meta *jiradata.EditMeta `yaml:"meta" json:"meta"`
Overrides map[string]string `yaml:"overrides" json:"overrides"` Overrides map[string]string `yaml:"overrides" json:"overrides"`
} }
if opts.Issue != "" { if opts.Issue != "" {
issueData, err := jc.GetIssue(opts.Issue, nil) issueData, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, nil)
if err != nil { if err != nil {
return err return err
} }
editMeta, err := jc.GetIssueEditMeta(opts.Issue) editMeta, err := jira.GetIssueEditMeta(o, opts.Endpoint.Value, opts.Issue)
if err != nil { if err != nil {
return err return err
} }
@@ -78,24 +80,24 @@ func (jc *JiraCli) CmdEdit(opts *EditOptions) error {
Meta: editMeta, Meta: editMeta,
Overrides: opts.Overrides, Overrides: opts.Overrides,
} }
err = jc.editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error { err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
return jc.EditIssue(opts.Issue, &issueUpdate) return jira.EditIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate)
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
} }
results, err := jc.Search(opts) results, err := jira.Search(o, opts.Endpoint.Value, opts)
if err != nil { if err != nil {
return err return err
} }
for _, issueData := range results.Issues { for _, issueData := range results.Issues {
editMeta, err := jc.GetIssueEditMeta(issueData.Key) editMeta, err := jira.GetIssueEditMeta(o, opts.Endpoint.Value, issueData.Key)
if err != nil { if err != nil {
return err return err
} }
@@ -105,16 +107,16 @@ func (jc *JiraCli) CmdEdit(opts *EditOptions) error {
Issue: issueData, Issue: issueData,
Meta: editMeta, Meta: editMeta,
} }
err = jc.editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error { err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
return jc.EditIssue(issueData.Key, &issueUpdate) return jira.EditIssue(o, opts.Endpoint.Value, issueData.Key, &issueUpdate)
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, jc.Endpoint, issueData.Key) fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, opts.Endpoint.Value, issueData.Key)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueData.Key}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueData.Key})
} }
} }
return nil return nil
+16 -13
View File
@@ -2,15 +2,17 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type EditMetaOptions struct { type EditMetaOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdEditMetaRegistry() *CommandRegistryEntry { func CmdEditMetaRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := EditMetaOptions{ opts := EditMetaOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
@@ -21,35 +23,36 @@ func (jc *JiraCli) CmdEditMetaRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"View 'edit' metadata", "View 'edit' metadata",
func() error { func() error {
return jc.CmdEditMeta(&opts) return CmdEditMeta(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdEditMetaUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdEditMetaUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdEditMetaUsage(cmd *kingpin.CmdClause, opts *EditMetaOptions) error { func CmdEditMetaUsage(cmd *kingpin.CmdClause, opts *EditMetaOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "edit metadata for issue id").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "edit metadata for issue id").Required().StringVar(&opts.Issue)
return nil return nil
} }
// EditMeta will get issue edit metadata and send to "editmeta" template // EditMeta will get issue edit metadata and send to "editmeta" template
func (jc *JiraCli) CmdEditMeta(opts *EditMetaOptions) error { func CmdEditMeta(o *oreo.Client, opts *EditMetaOptions) error {
editMeta, err := jc.GetIssueEditMeta(opts.Issue) editMeta, err := jira.GetIssueEditMeta(o, opts.Endpoint.Value, opts.Issue)
if err != nil { if err != nil {
return err return err
} }
if err := jc.runTemplate(opts.Template.Value, editMeta, nil); err != nil { if err := runTemplate(opts.Template.Value, editMeta, nil); err != nil {
return err return err
} }
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+9 -6
View File
@@ -5,6 +5,8 @@ import (
"os" "os"
"path" "path"
"github.com/coryb/figtree"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@@ -13,23 +15,24 @@ type ExportTemplatesOptions struct {
Dir string Dir string
} }
func (jc *JiraCli) CmdExportTemplatesRegistry() *CommandRegistryEntry { func CmdExportTemplatesRegistry(fig *figtree.FigTree) *CommandRegistryEntry {
opts := ExportTemplatesOptions{ opts := ExportTemplatesOptions{
Dir: fmt.Sprintf("%s/.jira.d/templates", homedir()), Dir: fmt.Sprintf("%s/.jira.d/templates", Homedir()),
} }
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Export templates for customizations", "Export templates for customizations",
func() error { func() error {
return jc.CmdExportTemplates(&opts) return CmdExportTemplates(&opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdExportTemplatesUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdExportTemplatesUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdExportTemplatesUsage(cmd *kingpin.CmdClause, opts *ExportTemplatesOptions) error { func CmdExportTemplatesUsage(cmd *kingpin.CmdClause, opts *ExportTemplatesOptions) error {
cmd.Flag("template", "Template to export").Short('t').StringVar(&opts.Template) cmd.Flag("template", "Template to export").Short('t').StringVar(&opts.Template)
cmd.Flag("dir", "directory to write tempates to").Short('d').StringVar(&opts.Dir) cmd.Flag("dir", "directory to write tempates to").Short('d').StringVar(&opts.Dir)
@@ -37,7 +40,7 @@ func (jc *JiraCli) CmdExportTemplatesUsage(cmd *kingpin.CmdClause, opts *ExportT
} }
// CmdExportTemplates will export templates to directory // CmdExportTemplates will export templates to directory
func (jc *JiraCli) CmdExportTemplates(opts *ExportTemplatesOptions) error { func CmdExportTemplates(opts *ExportTemplatesOptions) error {
if err := os.MkdirAll(opts.Dir, 0755); err != nil { if err := os.MkdirAll(opts.Dir, 0755); err != nil {
return err return err
} }
+10 -7
View File
@@ -2,31 +2,34 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
func (jc *JiraCli) CmdFieldsRegistry() *CommandRegistryEntry { func CmdFieldsRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := GlobalOptions{ opts := GlobalOptions{
Template: figtree.NewStringOption("fields"), Template: figtree.NewStringOption("fields"),
} }
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Prints all fields, both System and Custom", "Prints all fields, both System and Custom",
func() error { func() error {
return jc.CmdFields(&opts) return CmdFields(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
err := jc.GlobalUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
jc.TemplateUsage(cmd, &opts) err := GlobalUsage(cmd, &opts)
TemplateUsage(cmd, &opts)
return err return err
}, },
} }
} }
// Fields will send data from /rest/api/2/field API to "fields" template // Fields will send data from /rest/api/2/field API to "fields" template
func (jc *JiraCli) CmdFields(opts *GlobalOptions) error { func CmdFields(o *oreo.Client, opts *GlobalOptions) error {
data, err := jc.GetFields() data, err := jira.GetFields(o, opts.Endpoint.Value)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, data, nil) return runTemplate(opts.Template.Value, data, nil)
} }
+22 -17
View File
@@ -3,17 +3,21 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type IssueLinkOptions struct { type IssueLinkOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.LinkIssueRequest jiradata.LinkIssueRequest `yaml:",inline" figtree:",inline"`
LinkType string LinkType string
} }
func (jc *JiraCli) CmdIssueLinkRegistry() *CommandRegistryEntry { func CmdIssueLinkRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := IssueLinkOptions{ opts := IssueLinkOptions{
LinkIssueRequest: jiradata.LinkIssueRequest{ LinkIssueRequest: jiradata.LinkIssueRequest{
Type: &jiradata.IssueLinkType{}, Type: &jiradata.IssueLinkType{},
@@ -24,21 +28,22 @@ func (jc *JiraCli) CmdIssueLinkRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Link two issues", "Link two issues",
func() error { func() error {
return jc.CmdIssueLink(&opts) return CmdIssueLink(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdIssueLinkUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdIssueLinkUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdIssueLinkUsage(cmd *kingpin.CmdClause, opts *IssueLinkOptions) error { func CmdIssueLinkUsage(cmd *kingpin.CmdClause, opts *IssueLinkOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("comment", "Comment message when linking issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message when linking issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Comment = &jiradata.Comment{ opts.Comment = &jiradata.Comment{
Body: flagValue(ctx, "comment"), Body: flagValue(ctx, "comment"),
@@ -53,17 +58,17 @@ func (jc *JiraCli) CmdIssueLinkUsage(cmd *kingpin.CmdClause, opts *IssueLinkOpti
// CmdBlock will update the given issue as being a duplicate by the given dup issue // CmdBlock will update the given issue as being a duplicate by the given dup issue
// and will attempt to resolve the dup issue // and will attempt to resolve the dup issue
func (jc *JiraCli) CmdIssueLink(opts *IssueLinkOptions) error { func CmdIssueLink(o *oreo.Client, opts *IssueLinkOptions) error {
if err := jc.LinkIssues(&opts.LinkIssueRequest); err != nil { if err := jira.LinkIssues(o, opts.Endpoint.Value, &opts.LinkIssueRequest); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.InwardIssue.Key, jc.Endpoint, opts.InwardIssue.Key) fmt.Printf("OK %s %s/browse/%s\n", opts.InwardIssue.Key, opts.Endpoint.Value, opts.InwardIssue.Key)
fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, jc.Endpoint, opts.OutwardIssue.Key) fmt.Printf("OK %s %s/browse/%s\n", opts.OutwardIssue.Key, opts.Endpoint.Value, opts.OutwardIssue.Key)
if opts.Browse.Value { if opts.Browse.Value {
if err := jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.OutwardIssue.Key}); err != nil { if err := CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.OutwardIssue.Key}); err != nil {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.InwardIssue.Key}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.InwardIssue.Key})
} }
} }
+12 -9
View File
@@ -2,10 +2,12 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
func (jc *JiraCli) CmdIssueLinkTypesRegistry() *CommandRegistryEntry { func CmdIssueLinkTypesRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := GlobalOptions{ opts := GlobalOptions{
Template: figtree.NewStringOption("issuelinktypes"), Template: figtree.NewStringOption("issuelinktypes"),
} }
@@ -13,27 +15,28 @@ func (jc *JiraCli) CmdIssueLinkTypesRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Show the issue link types", "Show the issue link types",
func() error { func() error {
return jc.CmdIssueLinkTypes(&opts) return CmdIssueLinkTypes(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdIssueLinkTypesUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdIssueLinkTypesUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdIssueLinkTypesUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) error { func CmdIssueLinkTypesUsage(cmd *kingpin.CmdClause, opts *GlobalOptions) error {
if err := jc.GlobalUsage(cmd, opts); err != nil { if err := GlobalUsage(cmd, opts); err != nil {
return err return err
} }
jc.TemplateUsage(cmd, opts) TemplateUsage(cmd, opts)
return nil return nil
} }
// CmdIssueLinkTypes will get issue link type data and send to "issuelinktypes" template // CmdIssueLinkTypes will get issue link type data and send to "issuelinktypes" template
func (jc *JiraCli) CmdIssueLinkTypes(opts *GlobalOptions) error { func CmdIssueLinkTypes(o *oreo.Client, opts *GlobalOptions) error {
data, err := jc.GetIssueLinkTypes() data, err := jira.GetIssueLinkTypes(o, opts.Endpoint.Value)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, data, nil) return runTemplate(opts.Template.Value, data, nil)
} }
+14 -11
View File
@@ -4,16 +4,18 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type IssueTypesOptions struct { type IssueTypesOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Project string Project string
} }
func (jc *JiraCli) CmdIssueTypesRegistry() *CommandRegistryEntry { func CmdIssueTypesRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := IssueTypesOptions{ opts := IssueTypesOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("issuetypes"), Template: figtree.NewStringOption("issuetypes"),
@@ -23,32 +25,33 @@ func (jc *JiraCli) CmdIssueTypesRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Show issue types for a project", "Show issue types for a project",
func() error { func() error {
return jc.CmdIssueTypes(&opts) return CmdIssueTypes(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdIssueTypesUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdIssueTypesUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdIssueTypesUsage(cmd *kingpin.CmdClause, opts *IssueTypesOptions) error { func CmdIssueTypesUsage(cmd *kingpin.CmdClause, opts *IssueTypesOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("project", "project to list issueTypes").Short('p').StringVar(&opts.Project) cmd.Flag("project", "project to list issueTypes").Short('p').StringVar(&opts.Project)
return nil return nil
} }
// CmdIssueTypes will get available issueTypes for project and send to the "issueTypes" template // CmdIssueTypes will get available issueTypes for project and send to the "issueTypes" template
func (jc *JiraCli) CmdIssueTypes(opts *IssueTypesOptions) error { func CmdIssueTypes(o *oreo.Client, opts *IssueTypesOptions) error {
if opts.Project == "" { if opts.Project == "" {
return fmt.Errorf("Project Required.") return fmt.Errorf("Project Required.")
} }
data, err := jc.GetIssueCreateMetaProject(opts.Project) data, err := jira.GetIssueCreateMetaProject(o, opts.Endpoint.Value, opts.Project)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, data, nil) return runTemplate(opts.Template.Value, data, nil)
} }
+18 -13
View File
@@ -3,41 +3,46 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type LabelsAddOptions struct { type LabelsAddOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Labels []string Labels []string
} }
func (jc *JiraCli) CmdLabelsAddRegistry() *CommandRegistryEntry { func CmdLabelsAddRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := LabelsAddOptions{} opts := LabelsAddOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Add labels to an issue", "Add labels to an issue",
func() error { func() error {
return jc.CmdLabelsAdd(&opts) return CmdLabelsAdd(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdLabelsAddUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdLabelsAddUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdLabelsAddUsage(cmd *kingpin.CmdClause, opts *LabelsAddOptions) error { func CmdLabelsAddUsage(cmd *kingpin.CmdClause, opts *LabelsAddOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue)
cmd.Arg("LABEL", "label to add to issue").Required().StringsVar(&opts.Labels) cmd.Arg("LABEL", "label to add to issue").Required().StringsVar(&opts.Labels)
return nil return nil
} }
// CmdLabels will add labels on a given issue // CmdLabels will add labels on a given issue
func (jc *JiraCli) CmdLabelsAdd(opts *LabelsAddOptions) error { func CmdLabelsAdd(o *oreo.Client, opts *LabelsAddOptions) error {
ops := jiradata.FieldOperations{} ops := jiradata.FieldOperations{}
for _, label := range opts.Labels { for _, label := range opts.Labels {
ops = append(ops, jiradata.FieldOperation{ ops = append(ops, jiradata.FieldOperation{
@@ -50,12 +55,12 @@ func (jc *JiraCli) CmdLabelsAdd(opts *LabelsAddOptions) error {
}, },
} }
if err := jc.EditIssue(opts.Issue, &issueUpdate); err != nil { if err := jira.EditIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+18 -13
View File
@@ -3,41 +3,46 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type LabelsRemoveOptions struct { type LabelsRemoveOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Labels []string Labels []string
} }
func (jc *JiraCli) CmdLabelsRemoveRegistry() *CommandRegistryEntry { func CmdLabelsRemoveRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := LabelsRemoveOptions{} opts := LabelsRemoveOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Remove labels from an issue", "Remove labels from an issue",
func() error { func() error {
return jc.CmdLabelsRemove(&opts) return CmdLabelsRemove(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdLabelsRemoveUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdLabelsRemoveUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdLabelsRemoveUsage(cmd *kingpin.CmdClause, opts *LabelsRemoveOptions) error { func CmdLabelsRemoveUsage(cmd *kingpin.CmdClause, opts *LabelsRemoveOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue)
cmd.Arg("LABEL", "label to remove from issue").Required().StringsVar(&opts.Labels) cmd.Arg("LABEL", "label to remove from issue").Required().StringsVar(&opts.Labels)
return nil return nil
} }
// CmdLabels will remove labels on a given issue // CmdLabels will remove labels on a given issue
func (jc *JiraCli) CmdLabelsRemove(opts *LabelsRemoveOptions) error { func CmdLabelsRemove(o *oreo.Client, opts *LabelsRemoveOptions) error {
ops := jiradata.FieldOperations{} ops := jiradata.FieldOperations{}
for _, label := range opts.Labels { for _, label := range opts.Labels {
ops = append(ops, jiradata.FieldOperation{ ops = append(ops, jiradata.FieldOperation{
@@ -50,13 +55,13 @@ func (jc *JiraCli) CmdLabelsRemove(opts *LabelsRemoveOptions) error {
}, },
} }
err := jc.EditIssue(opts.Issue, &issueUpdate) err := jira.EditIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+18 -13
View File
@@ -3,41 +3,46 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type LabelsSetOptions struct { type LabelsSetOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Labels []string Labels []string
} }
func (jc *JiraCli) CmdLabelsSetRegistry() *CommandRegistryEntry { func CmdLabelsSetRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := LabelsSetOptions{} opts := LabelsSetOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Set labels on an issue", "Set labels on an issue",
func() error { func() error {
return jc.CmdLabelsSet(&opts) return CmdLabelsSet(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdLabelsSetUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdLabelsSetUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdLabelsSetUsage(cmd *kingpin.CmdClause, opts *LabelsSetOptions) error { func CmdLabelsSetUsage(cmd *kingpin.CmdClause, opts *LabelsSetOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue id to modify labels").Required().StringVar(&opts.Issue)
cmd.Arg("LABEL", "label to set on issue").Required().StringsVar(&opts.Labels) cmd.Arg("LABEL", "label to set on issue").Required().StringsVar(&opts.Labels)
return nil return nil
} }
// CmdLabels will set labels on a given issue // CmdLabels will set labels on a given issue
func (jc *JiraCli) CmdLabelsSet(opts *LabelsSetOptions) error { func CmdLabelsSet(o *oreo.Client, opts *LabelsSetOptions) error {
issueUpdate := jiradata.IssueUpdate{ issueUpdate := jiradata.IssueUpdate{
Update: jiradata.FieldOperationsMap{ Update: jiradata.FieldOperationsMap{
"labels": jiradata.FieldOperations{ "labels": jiradata.FieldOperations{
@@ -48,12 +53,12 @@ func (jc *JiraCli) CmdLabelsSet(opts *LabelsSetOptions) error {
}, },
} }
if err := jc.EditIssue(opts.Issue, &issueUpdate); err != nil { if err := jira.EditIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+11 -13
View File
@@ -2,6 +2,7 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1" jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@@ -11,7 +12,7 @@ type ListOptions struct {
jira.SearchOptions `yaml:",inline" figtree:",inline"` jira.SearchOptions `yaml:",inline" figtree:",inline"`
} }
func (jc *JiraCli) CmdListRegistry() *CommandRegistryEntry { func CmdListRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := ListOptions{ opts := ListOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("list"), Template: figtree.NewStringOption("list"),
@@ -26,22 +27,20 @@ func (jc *JiraCli) CmdListRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Prints list of issues for given search criteria", "Prints list of issues for given search criteria",
func() error { func() error {
return jc.CmdList(&opts) return CmdList(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdListUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdListUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdListUsage(cmd *kingpin.CmdClause, opts *ListOptions) error { func CmdListUsage(cmd *kingpin.CmdClause, opts *ListOptions) error {
log.Debugf("Configs: %#v", opts) if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
jc.LoadConfigs(cmd, opts)
log.Debugf("Configs: %#v", opts)
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("assignee", "User assigned the issue").Short('a').StringVar(&opts.Assignee) cmd.Flag("assignee", "User assigned the issue").Short('a').StringVar(&opts.Assignee)
cmd.Flag("component", "Component to search for").Short('c').StringVar(&opts.Component) cmd.Flag("component", "Component to search for").Short('c').StringVar(&opts.Component)
cmd.Flag("issuetype", "Issue type to search for").Short('i').StringVar(&opts.IssueType) cmd.Flag("issuetype", "Issue type to search for").Short('i').StringVar(&opts.IssueType)
@@ -56,11 +55,10 @@ func (jc *JiraCli) CmdListUsage(cmd *kingpin.CmdClause, opts *ListOptions) error
} }
// List will query jira and send data to "list" template // List will query jira and send data to "list" template
func (jc *JiraCli) CmdList(opts *ListOptions) error { func CmdList(o *oreo.Client, opts *ListOptions) error {
log.Debugf("Configs: %#v", opts) data, err := jira.Search(o, opts.Endpoint.Value, opts)
data, err := jc.Search(opts)
if err != nil { if err != nil {
return err return err
} }
return jc.runTemplate(opts.Template.Value, data, nil) return runTemplate(opts.Template.Value, data, nil)
} }
+10 -11
View File
@@ -4,20 +4,23 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
"github.com/mgutz/ansi" "github.com/mgutz/ansi"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1" jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
func (jc *JiraCli) CmdLoginRegistry() *CommandRegistryEntry { func CmdLoginRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := GlobalOptions{} opts := GlobalOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Attempt to login into jira server", "Attempt to login into jira server",
func() error { func() error {
return jc.CmdLogin(&opts) return CmdLogin(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.GlobalUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return GlobalUsage(cmd, &opts)
}, },
} }
} }
@@ -41,15 +44,11 @@ func authCallback(req *http.Request, resp *http.Response) (*http.Response, error
} }
// CmdLogin will attempt to login into jira server // CmdLogin will attempt to login into jira server
func (jc *JiraCli) CmdLogin(opts *GlobalOptions) error { func CmdLogin(o *oreo.Client, opts *GlobalOptions) error {
defer func(h jira.HttpClient) { if session, err := jira.GetSession(o, opts.Endpoint.Value); err != nil {
log.Debugf("Client: %#v", h) ua := o.WithoutRedirect().WithRetries(0).WithPostCallback(authCallback)
jc.UA = h
}(jc.UA)
if session, err := jc.GetSession(); err != nil {
jc.UA = jc.oreoAgent.WithoutRedirect().WithRetries(0).WithPostCallback(authCallback)
// No active session so try to create a new one // No active session so try to create a new one
_, err := jc.NewSession(opts) _, err := jira.NewSession(ua, opts.Endpoint.Value, opts)
if err != nil { if err != nil {
// reset password on failed session // reset password on failed session
opts.SetPass("") opts.SetPass("")
+10 -6
View File
@@ -3,27 +3,31 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
"github.com/mgutz/ansi" "github.com/mgutz/ansi"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
func (jc *JiraCli) CmdLogoutRegistry() *CommandRegistryEntry { func CmdLogoutRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := GlobalOptions{} opts := GlobalOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Deactivate sesssion with Jira server", "Deactivate sesssion with Jira server",
func() error { func() error {
return jc.CmdLogout(&opts) return CmdLogout(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.GlobalUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return GlobalUsage(cmd, &opts)
}, },
} }
} }
// CmdLogout will attempt to terminate an active Jira session // CmdLogout will attempt to terminate an active Jira session
func (jc *JiraCli) CmdLogout(opts *GlobalOptions) error { func CmdLogout(o *oreo.Client, opts *GlobalOptions) error {
jc.UA = jc.oreoAgent.WithoutRedirect().WithRetries(0) ua := o.WithoutRedirect().WithRetries(0)
err := jc.DeleteSession() err := jira.DeleteSession(ua, opts.Endpoint.Value)
if err == nil { if err == nil {
fmt.Println(ansi.Color("OK", "green"), "Terminated session for", opts.User) fmt.Println(ansi.Color("OK", "green"), "Terminated session for", opts.User)
} else { } else {
+21 -16
View File
@@ -3,18 +3,22 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type RankOptions struct { type RankOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
First string First string
Second string Second string
Order string Order string
} }
func (jc *JiraCli) CmdRankRegistry() *CommandRegistryEntry { func CmdRankRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := RankOptions{ opts := RankOptions{
GlobalOptions: GlobalOptions{}, GlobalOptions: GlobalOptions{},
} }
@@ -22,19 +26,20 @@ func (jc *JiraCli) CmdRankRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Mark issues as blocker", "Mark issues as blocker",
func() error { func() error {
return jc.CmdRank(&opts) return CmdRank(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdRankUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdRankUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdRankUsage(cmd *kingpin.CmdClause, opts *RankOptions) error { func CmdRankUsage(cmd *kingpin.CmdClause, opts *RankOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("FIRST-ISSUE", "first issue").Required().StringVar(&opts.First) cmd.Arg("FIRST-ISSUE", "first issue").Required().StringVar(&opts.First)
cmd.Arg("after|before", "rank ordering").Required().HintOptions("after", "before").EnumVar(&opts.Order, "after", "before") cmd.Arg("after|before", "rank ordering").Required().HintOptions("after", "before").EnumVar(&opts.Order, "after", "before")
cmd.Arg("SECOND-ISSUE", "second issue").Required().StringVar(&opts.Second) cmd.Arg("SECOND-ISSUE", "second issue").Required().StringVar(&opts.Second)
@@ -42,7 +47,7 @@ func (jc *JiraCli) CmdRankUsage(cmd *kingpin.CmdClause, opts *RankOptions) error
} }
// CmdRank order two issue // CmdRank order two issue
func (jc *JiraCli) CmdRank(opts *RankOptions) error { func CmdRank(o *oreo.Client, opts *RankOptions) error {
req := &jiradata.RankRequest{ req := &jiradata.RankRequest{
Issues: []string{opts.First}, Issues: []string{opts.First},
} }
@@ -53,16 +58,16 @@ func (jc *JiraCli) CmdRank(opts *RankOptions) error {
req.RankBeforeIssue = opts.Second req.RankBeforeIssue = opts.Second
} }
if err := jc.RankIssues(req); err != nil { if err := jira.RankIssues(o, opts.Endpoint.Value, req); err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.First, jc.Endpoint, opts.First) fmt.Printf("OK %s %s/browse/%s\n", opts.First, opts.Endpoint.Value, opts.First)
fmt.Printf("OK %s %s/browse/%s\n", opts.Second, jc.Endpoint, opts.Second) fmt.Printf("OK %s %s/browse/%s\n", opts.Second, opts.Endpoint.Value, opts.Second)
if opts.Browse.Value { if opts.Browse.Value {
if err := jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.First}); err != nil { if err := CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.First}); err != nil {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Second}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Second})
} }
} }
+14 -13
View File
@@ -14,13 +14,13 @@ import (
) )
type RequestOptions struct { type RequestOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Method string Method string
URI string URI string
Data string Data string
} }
func (jc *JiraCli) CmdRequestRegistry() *CommandRegistryEntry { func CmdRequestRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := RequestOptions{ opts := RequestOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("request"), Template: figtree.NewStringOption("request"),
@@ -31,16 +31,17 @@ func (jc *JiraCli) CmdRequestRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Open issue in requestr", "Open issue in requestr",
func() error { func() error {
return jc.CmdRequest(&opts) return CmdRequest(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdRequestUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdRequestUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdRequestUsage(cmd *kingpin.CmdClause, opts *RequestOptions) error { func CmdRequestUsage(cmd *kingpin.CmdClause, opts *RequestOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
cmd.Flag("method", "HTTP request method to use").Short('m').EnumVar(&opts.Method, "GET", "PUT", "POST", "DELETE") cmd.Flag("method", "HTTP request method to use").Short('m').EnumVar(&opts.Method, "GET", "PUT", "POST", "DELETE")
@@ -51,10 +52,10 @@ func (jc *JiraCli) CmdRequestUsage(cmd *kingpin.CmdClause, opts *RequestOptions)
} }
// CmdRequest open the default system requestr to the provided issue // CmdRequest open the default system requestr to the provided issue
func (jc *JiraCli) CmdRequest(opts *RequestOptions) error { func CmdRequest(o *oreo.Client, opts *RequestOptions) error {
uri := opts.URI uri := opts.URI
if !strings.HasPrefix(uri, "http") { if !strings.HasPrefix(uri, "http") {
uri = jc.Endpoint + uri uri = opts.Endpoint.Value + uri
} }
parsedURI, err := url.Parse(uri) parsedURI, err := url.Parse(uri)
@@ -66,7 +67,7 @@ func (jc *JiraCli) CmdRequest(opts *RequestOptions) error {
builder = builder.WithJSON(opts.Data) builder = builder.WithJSON(opts.Data)
} }
resp, err := jc.UA.Do(builder.Build()) resp, err := o.Do(builder.Build())
if err != nil { if err != nil {
return err return err
} }
@@ -86,5 +87,5 @@ func (jc *JiraCli) CmdRequest(opts *RequestOptions) error {
return fmt.Errorf("JSON Parse Error: %s from %q", err, content) return fmt.Errorf("JSON Parse Error: %s from %q", err, content)
} }
return jc.runTemplate(opts.Template.Value, &data, nil) return runTemplate(opts.Template.Value, &data, nil)
} }
+24 -21
View File
@@ -4,21 +4,23 @@ import (
"fmt" "fmt"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type SubtaskOptions struct { type SubtaskOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.IssueUpdate jiradata.IssueUpdate `yaml:",inline" figtree:",inline"`
Project string Project string
IssueType string IssueType string
Overrides map[string]string Overrides map[string]string
Issue string Issue string
} }
func (jc *JiraCli) CmdSubtaskRegistry() *CommandRegistryEntry { func CmdSubtaskRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := SubtaskOptions{ opts := SubtaskOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("subtask"), Template: figtree.NewStringOption("subtask"),
@@ -30,21 +32,22 @@ func (jc *JiraCli) CmdSubtaskRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Subtask issue", "Subtask issue",
func() error { func() error {
return jc.CmdSubtask(&opts) return CmdSubtask(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdSubtaskUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdSubtaskUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdSubtaskUsage(cmd *kingpin.CmdClause, opts *SubtaskOptions) error { func CmdSubtaskUsage(cmd *kingpin.CmdClause, opts *SubtaskOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing) cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
cmd.Flag("project", "project to subtask issue in").Short('p').StringVar(&opts.Project) cmd.Flag("project", "project to subtask issue in").Short('p').StringVar(&opts.Project)
cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
@@ -58,14 +61,14 @@ func (jc *JiraCli) CmdSubtaskUsage(cmd *kingpin.CmdClause, opts *SubtaskOptions)
// CmdSubtask sends the subtask-metadata to the "subtask" template for editing, then // CmdSubtask sends the subtask-metadata to the "subtask" template for editing, then
// will parse the edited document as YAML and submit the document to jira. // will parse the edited document as YAML and submit the document to jira.
func (jc *JiraCli) CmdSubtask(opts *SubtaskOptions) error { func CmdSubtask(o *oreo.Client, opts *SubtaskOptions) error {
type templateInput struct { type templateInput struct {
Meta *jiradata.CreateMetaIssueType `yaml:"meta" json:"meta"` Meta *jiradata.CreateMetaIssueType `yaml:"meta" json:"meta"`
Overrides map[string]string `yaml:"overrides" json:"overrides"` Overrides map[string]string `yaml:"overrides" json:"overrides"`
Parent *jiradata.Issue `yaml:"parent" json:"parent"` Parent *jiradata.Issue `yaml:"parent" json:"parent"`
} }
parent, err := jc.GetIssue(opts.Issue, nil) parent, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -80,7 +83,7 @@ func (jc *JiraCli) CmdSubtask(opts *SubtaskOptions) error {
return fmt.Errorf("Failed to find Project field in parent issue") return fmt.Errorf("Failed to find Project field in parent issue")
} }
createMeta, err := jc.GetIssueCreateMetaIssueType(opts.Project, opts.IssueType) createMeta, err := jira.GetIssueCreateMetaIssueType(o, opts.Endpoint.Value, opts.Project, opts.IssueType)
if err != nil { if err != nil {
return err return err
} }
@@ -96,18 +99,18 @@ func (jc *JiraCli) CmdSubtask(opts *SubtaskOptions) error {
input.Overrides["user"] = opts.User.Value input.Overrides["user"] = opts.User.Value
var issueResp *jiradata.IssueCreateResponse var issueResp *jiradata.IssueCreateResponse
err = jc.editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error { err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
issueResp, err = jc.CreateIssue(&issueUpdate) issueResp, err = jira.CreateIssue(o, opts.Endpoint.Value, &issueUpdate)
return err return err
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", issueResp.Key, jc.Endpoint, issueResp.Key) fmt.Printf("OK %s %s/browse/%s\n", issueResp.Key, opts.Endpoint.Value, issueResp.Key)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueResp.Key}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, issueResp.Key})
} }
return nil return nil
} }
+12 -7
View File
@@ -1,27 +1,32 @@
package jiracli package jiracli
import kingpin "gopkg.in/alecthomas/kingpin.v2" import (
"github.com/coryb/figtree"
"github.com/coryb/oreo"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
func (jc *JiraCli) CmdTakeRegistry() *CommandRegistryEntry { func CmdTakeRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := AssignOptions{} opts := AssignOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Assign issue to yourself", "Assign issue to yourself",
func() error { func() error {
opts.Assignee = opts.User.Value opts.Assignee = opts.User.Value
return jc.CmdAssign(&opts) return CmdAssign(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdAssignUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdAssignUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdTakeUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error { func CmdTakeUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue to assign").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue to assign").Required().StringVar(&opts.Issue)
return nil return nil
} }
+6 -6
View File
@@ -28,7 +28,7 @@ func findTemplate(name string) ([]byte, error) {
return nil, nil return nil, nil
} }
func (jc *JiraCli) getTemplate(name string) (string, error) { func getTemplate(name string) (string, error) {
if _, err := os.Stat(name); err == nil { if _, err := os.Stat(name); err == nil {
b, err := ioutil.ReadFile(name) b, err := ioutil.ReadFile(name)
if err != nil { if err != nil {
@@ -48,18 +48,18 @@ func (jc *JiraCli) getTemplate(name string) (string, error) {
return "", fmt.Errorf("No Template found for %q", name) return "", fmt.Errorf("No Template found for %q", name)
} }
func (jc *JiraCli) tmpTemplate(templateName string, data interface{}) (string, error) { func tmpTemplate(templateName string, data interface{}) (string, error) {
tmpFile, err := jc.tmpYml(templateName) tmpFile, err := tmpYml(templateName)
if err != nil { if err != nil {
return "", err return "", err
} }
defer tmpFile.Close() defer tmpFile.Close()
return tmpFile.Name(), jc.runTemplate(templateName, data, tmpFile) return tmpFile.Name(), runTemplate(templateName, data, tmpFile)
} }
func (jc *JiraCli) runTemplate(templateName string, data interface{}, out io.Writer) error { func runTemplate(templateName string, data interface{}, out io.Writer) error {
templateContent, err := jc.getTemplate(templateName) templateContent, err := getTemplate(templateName)
if err != nil { if err != nil {
return err return err
} }
+22 -19
View File
@@ -5,20 +5,22 @@ import (
"strings" "strings"
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type TransitionOptions struct { type TransitionOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Overrides map[string]string Overrides map[string]string
Transition string Transition string
Issue string Issue string
Resolution string Resolution string
} }
func (jc *JiraCli) CmdTransitionRegistry(transition string) *CommandRegistryEntry { func CmdTransitionRegistry(fig *figtree.FigTree, o *oreo.Client, transition string) *CommandRegistryEntry {
opts := TransitionOptions{ opts := TransitionOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("transition"), Template: figtree.NewStringOption("transition"),
@@ -35,20 +37,21 @@ func (jc *JiraCli) CmdTransitionRegistry(transition string) *CommandRegistryEntr
return &CommandRegistryEntry{ return &CommandRegistryEntry{
help, help,
func() error { func() error {
return jc.CmdTransition(&opts) return CmdTransition(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdTransitionUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdTransitionUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error { func CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Overrides["comment"] = flagValue(ctx, "comment") opts.Overrides["comment"] = flagValue(ctx, "comment")
return nil return nil
@@ -62,13 +65,13 @@ func (jc *JiraCli) CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOp
} }
// CmdTransition will move state of the given issue to the given transtion // CmdTransition will move state of the given issue to the given transtion
func (jc *JiraCli) CmdTransition(opts *TransitionOptions) error { func CmdTransition(o *oreo.Client, opts *TransitionOptions) error {
issueData, err := jc.GetIssue(opts.Issue, nil) issueData, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, nil)
if err != nil { if err != nil {
return err return err
} }
meta, err := jc.GetIssueTransitions(opts.Issue) meta, err := jira.GetIssueTransitions(o, opts.Endpoint.Value, opts.Issue)
if err != nil { if err != nil {
return err return err
} }
@@ -120,16 +123,16 @@ func (jc *JiraCli) CmdTransition(opts *TransitionOptions) error {
Transition: transMeta, Transition: transMeta,
Overrides: opts.Overrides, Overrides: opts.Overrides,
} }
err = jc.editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error { err = editLoop(&opts.GlobalOptions, &input, &issueUpdate, func() error {
return jc.TransitionIssue(opts.Issue, &issueUpdate) return jira.TransitionIssue(o, opts.Endpoint.Value, opts.Issue, &issueUpdate)
}) })
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, jc.Endpoint, issueData.Key) fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, opts.Endpoint.Value, issueData.Key)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+16 -13
View File
@@ -2,15 +2,17 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type TransitionsOptions struct { type TransitionsOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdTransitionsRegistry(defaultTemplate string) *CommandRegistryEntry { func CmdTransitionsRegistry(fig *figtree.FigTree, o *oreo.Client, defaultTemplate string) *CommandRegistryEntry {
opts := TransitionsOptions{ opts := TransitionsOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption(defaultTemplate), Template: figtree.NewStringOption(defaultTemplate),
@@ -20,35 +22,36 @@ func (jc *JiraCli) CmdTransitionsRegistry(defaultTemplate string) *CommandRegist
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"List valid issue transitions", "List valid issue transitions",
func() error { func() error {
return jc.CmdTransitions(&opts) return CmdTransitions(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdTransitionsUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdTransitionsUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdTransitionsUsage(cmd *kingpin.CmdClause, opts *TransitionsOptions) error { func CmdTransitionsUsage(cmd *kingpin.CmdClause, opts *TransitionsOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue to list valid transitions").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue to list valid transitions").Required().StringVar(&opts.Issue)
return nil return nil
} }
// Transitions will get issue edit metadata and send to "editmeta" template // Transitions will get issue edit metadata and send to "editmeta" template
func (jc *JiraCli) CmdTransitions(opts *TransitionsOptions) error { func CmdTransitions(o *oreo.Client, opts *TransitionsOptions) error {
editMeta, err := jc.GetIssueTransitions(opts.Issue) editMeta, err := jira.GetIssueTransitions(o, opts.Endpoint.Value, opts.Issue)
if err != nil { if err != nil {
return err return err
} }
if err := jc.runTemplate(opts.Template.Value, editMeta, nil); err != nil { if err := runTemplate(opts.Template.Value, editMeta, nil); err != nil {
return err return err
} }
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+12 -7
View File
@@ -1,26 +1,31 @@
package jiracli package jiracli
import kingpin "gopkg.in/alecthomas/kingpin.v2" import (
"github.com/coryb/figtree"
"github.com/coryb/oreo"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
func (jc *JiraCli) CmdUnassignRegistry() *CommandRegistryEntry { func CmdUnassignRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := AssignOptions{} opts := AssignOptions{}
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Unassign an issue", "Unassign an issue",
func() error { func() error {
return jc.CmdAssign(&opts) return CmdAssign(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdAssignUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdAssignUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdUnassignUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error { func CmdUnassignUsage(cmd *kingpin.CmdClause, opts *AssignOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue to unassign").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue to unassign").Required().StringVar(&opts.Issue)
return nil return nil
} }
+8 -5
View File
@@ -7,27 +7,30 @@ import (
"os" "os"
"path" "path"
"github.com/coryb/figtree"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
func (jc *JiraCli) CmdUnexportTemplatesRegistry() *CommandRegistryEntry { func CmdUnexportTemplatesRegistry(fig *figtree.FigTree) *CommandRegistryEntry {
opts := ExportTemplatesOptions{ opts := ExportTemplatesOptions{
Dir: fmt.Sprintf("%s/.jira.d/templates", homedir()), Dir: fmt.Sprintf("%s/.jira.d/templates", Homedir()),
} }
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Remove unmodified exported templates", "Remove unmodified exported templates",
func() error { func() error {
return jc.CmdUnexportTemplates(&opts) return CmdUnexportTemplates(&opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdExportTemplatesUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdExportTemplatesUsage(cmd, &opts)
}, },
} }
} }
// CmdUnexportTemplates will remove unmodified templates from export directory // CmdUnexportTemplates will remove unmodified templates from export directory
func (jc *JiraCli) CmdUnexportTemplates(opts *ExportTemplatesOptions) error { func CmdUnexportTemplates(opts *ExportTemplatesOptions) error {
for name, template := range allTemplates { for name, template := range allTemplates {
if opts.Template != "" && opts.Template != name { if opts.Template != "" && opts.Template != name {
continue continue
+3 -9
View File
@@ -6,7 +6,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"runtime" "runtime"
"time" "time"
@@ -15,7 +14,7 @@ import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
) )
func homedir() string { func Homedir() string {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
return os.Getenv("USERPROFILE") return os.Getenv("USERPROFILE")
} }
@@ -30,13 +29,8 @@ func findClosestParentPath(fileName string) (string, error) {
return "", errors.New(fmt.Sprintf("%s not found in parent directory hierarchy", fileName)) return "", errors.New(fmt.Sprintf("%s not found in parent directory hierarchy", fileName))
} }
func (jc *JiraCli) tmpYml(tmpFilePrefix string) (*os.File, error) { func tmpYml(tmpFilePrefix string) (*os.File, error) {
tmpdir := filepath.Join(homedir(), jc.ConfigDir, "tmp") fh, err := ioutil.TempFile("", tmpFilePrefix)
if err := os.MkdirAll(tmpdir, 0755); err != nil {
return nil, err
}
fh, err := ioutil.TempFile(tmpdir, tmpFilePrefix)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+16 -14
View File
@@ -2,17 +2,18 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1" jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type ViewOptions struct { type ViewOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jira.IssueOptions jira.IssueOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdViewRegistry() *CommandRegistryEntry { func CmdViewRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := ViewOptions{ opts := ViewOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("view"), Template: figtree.NewStringOption("view"),
@@ -22,20 +23,21 @@ func (jc *JiraCli) CmdViewRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Prints issue details", "Prints issue details",
func() error { func() error {
return jc.CmdView(&opts) return CmdView(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdViewUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdViewUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdViewUsage(cmd *kingpin.CmdClause, opts *ViewOptions) error { func CmdViewUsage(cmd *kingpin.CmdClause, opts *ViewOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("expand", "field to expand for the issue").StringsVar(&opts.Expand) cmd.Flag("expand", "field to expand for the issue").StringsVar(&opts.Expand)
cmd.Flag("field", "field to return for the issue").StringsVar(&opts.Fields) cmd.Flag("field", "field to return for the issue").StringsVar(&opts.Fields)
cmd.Flag("property", "property to return for issue").StringsVar(&opts.Properties) cmd.Flag("property", "property to return for issue").StringsVar(&opts.Properties)
@@ -44,16 +46,16 @@ func (jc *JiraCli) CmdViewUsage(cmd *kingpin.CmdClause, opts *ViewOptions) error
} }
// View will get issue data and send to "view" template // View will get issue data and send to "view" template
func (jc *JiraCli) CmdView(opts *ViewOptions) error { func CmdView(o *oreo.Client, opts *ViewOptions) error {
data, err := jc.GetIssue(opts.Issue, opts) data, err := jira.GetIssue(o, opts.Endpoint.Value, opts.Issue, opts)
if err != nil { if err != nil {
return err return err
} }
if err := jc.runTemplate(opts.Template.Value, data, nil); err != nil { if err := runTemplate(opts.Template.Value, data, nil); err != nil {
return err return err
} }
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+19 -14
View File
@@ -3,6 +3,10 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@@ -14,12 +18,12 @@ const (
) )
type VoteOptions struct { type VoteOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Action VoteAction Action VoteAction
} }
func (jc *JiraCli) CmdVoteRegistry() *CommandRegistryEntry { func CmdVoteRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := VoteOptions{ opts := VoteOptions{
GlobalOptions: GlobalOptions{}, GlobalOptions: GlobalOptions{},
Action: VoteUP, Action: VoteUP,
@@ -28,19 +32,20 @@ func (jc *JiraCli) CmdVoteRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Vote up/down an issue", "Vote up/down an issue",
func() error { func() error {
return jc.CmdVote(&opts) return CmdVote(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdVoteUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdVoteUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdVoteUsage(cmd *kingpin.CmdClause, opts *VoteOptions) error { func CmdVoteUsage(cmd *kingpin.CmdClause, opts *VoteOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Flag("down", "downvote the issue").Short('d').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("down", "downvote the issue").Short('d').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Action = VoteDown opts.Action = VoteDown
return nil return nil
@@ -50,20 +55,20 @@ func (jc *JiraCli) CmdVoteUsage(cmd *kingpin.CmdClause, opts *VoteOptions) error
} }
// Vote will up/down vote an issue // Vote will up/down vote an issue
func (jc *JiraCli) CmdVote(opts *VoteOptions) error { func CmdVote(o *oreo.Client, opts *VoteOptions) error {
if opts.Action == VoteUP { if opts.Action == VoteUP {
if err := jc.IssueAddVote(opts.Issue); err != nil { if err := jira.IssueAddVote(o, opts.Endpoint.Value, opts.Issue); err != nil {
return err return err
} }
} else { } else {
if err := jc.IssueRemoveVote(opts.Issue); err != nil { if err := jira.IssueRemoveVote(o, opts.Endpoint.Value, opts.Issue); err != nil {
return err return err
} }
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+20 -15
View File
@@ -3,6 +3,10 @@ package jiracli
import ( import (
"fmt" "fmt"
"github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@@ -14,13 +18,13 @@ const (
) )
type WatchOptions struct { type WatchOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
Watcher string Watcher string
Action WatchAction Action WatchAction
} }
func (jc *JiraCli) CmdWatchRegistry() *CommandRegistryEntry { func CmdWatchRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := WatchOptions{ opts := WatchOptions{
GlobalOptions: GlobalOptions{}, GlobalOptions: GlobalOptions{},
Action: WatcherAdd, Action: WatcherAdd,
@@ -29,19 +33,20 @@ func (jc *JiraCli) CmdWatchRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Add/Remove watcher to issue", "Add/Remove watcher to issue",
func() error { func() error {
return jc.CmdWatch(&opts) return CmdWatch(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdWatchUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdWatchUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdWatchUsage(cmd *kingpin.CmdClause, opts *WatchOptions) error { func CmdWatchUsage(cmd *kingpin.CmdClause, opts *WatchOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
cmd.Flag("remove", "remove watcher from issue").Short('r').PreAction(func(ctx *kingpin.ParseContext) error { cmd.Flag("remove", "remove watcher from issue").Short('r').PreAction(func(ctx *kingpin.ParseContext) error {
opts.Action = WatcherRemove opts.Action = WatcherRemove
return nil return nil
@@ -53,24 +58,24 @@ func (jc *JiraCli) CmdWatchUsage(cmd *kingpin.CmdClause, opts *WatchOptions) err
// CmdWatch will add the given watcher to the issue (or remove the watcher // CmdWatch will add the given watcher to the issue (or remove the watcher
// with the 'remove' flag) // with the 'remove' flag)
func (jc *JiraCli) CmdWatch(opts *WatchOptions) error { func CmdWatch(o *oreo.Client, opts *WatchOptions) error {
if opts.Watcher == "" { if opts.Watcher == "" {
opts.Watcher = opts.User.Value opts.Watcher = opts.User.Value
} }
if opts.Action == WatcherAdd { if opts.Action == WatcherAdd {
if err := jc.IssueAddWatcher(opts.Issue, opts.Watcher); err != nil { if err := jira.IssueAddWatcher(o, opts.Endpoint.Value, opts.Issue, opts.Watcher); err != nil {
return err return err
} }
} else { } else {
if err := jc.IssueRemoveWatcher(opts.Issue, opts.Watcher); err != nil { if err := jira.IssueRemoveWatcher(o, opts.Endpoint.Value, opts.Issue, opts.Watcher); err != nil {
return err return err
} }
} }
fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, jc.Endpoint, opts.Issue) fmt.Printf("OK %s %s/browse/%s\n", opts.Issue, opts.Endpoint.Value, opts.Issue)
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
+18 -15
View File
@@ -2,17 +2,19 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata" "gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type WorklogAddOptions struct { type WorklogAddOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
jiradata.Worklog jiradata.Worklog `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdWorklogAddRegistry() *CommandRegistryEntry { func CmdWorklogAddRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := WorklogAddOptions{ opts := WorklogAddOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("worklog"), Template: figtree.NewStringOption("worklog"),
@@ -21,21 +23,22 @@ func (jc *JiraCli) CmdWorklogAddRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Add a worklog to an issue", "Add a worklog to an issue",
func() error { func() error {
return jc.CmdWorklogAdd(&opts) return CmdWorklogAdd(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdWorklogAddUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdWorklogAddUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdWorklogAddUsage(cmd *kingpin.CmdClause, opts *WorklogAddOptions) error { func CmdWorklogAddUsage(cmd *kingpin.CmdClause, opts *WorklogAddOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.EditorUsage(cmd, &opts.GlobalOptions) EditorUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing) cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
cmd.Flag("comment", "Comment message for worklog").Short('m').StringVar(&opts.Comment) cmd.Flag("comment", "Comment message for worklog").Short('m').StringVar(&opts.Comment)
cmd.Flag("time-spent", "Time spent working on issue").Short('T').StringVar(&opts.TimeSpent) cmd.Flag("time-spent", "Time spent working on issue").Short('T').StringVar(&opts.TimeSpent)
@@ -46,16 +49,16 @@ func (jc *JiraCli) CmdWorklogAddUsage(cmd *kingpin.CmdClause, opts *WorklogAddOp
// CmdWorklogAdd will attempt to add (action=add) a worklog to the given issue. // CmdWorklogAdd will attempt to add (action=add) a worklog to the given issue.
// It will spawn the editor (unless --noedit isused) and post edited YAML // It will spawn the editor (unless --noedit isused) and post edited YAML
// content as JSON to the worklog endpoint // content as JSON to the worklog endpoint
func (jc *JiraCli) CmdWorklogAdd(opts *WorklogAddOptions) error { func CmdWorklogAdd(o *oreo.Client, opts *WorklogAddOptions) error {
err := jc.editLoop(&opts.GlobalOptions, &opts.Worklog, &opts.Worklog, func() error { err := editLoop(&opts.GlobalOptions, &opts.Worklog, &opts.Worklog, func() error {
_, err := jc.AddIssueWorklog(opts.Issue, opts) _, err := jira.AddIssueWorklog(o, opts.Endpoint.Value, opts.Issue, opts)
return err return err
}) })
if err != nil { if err != nil {
return err return err
} }
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+16 -13
View File
@@ -2,15 +2,17 @@ package jiracli
import ( import (
"github.com/coryb/figtree" "github.com/coryb/figtree"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
type WorklogListOptions struct { type WorklogListOptions struct {
GlobalOptions GlobalOptions `yaml:",inline" figtree:",inline"`
Issue string Issue string
} }
func (jc *JiraCli) CmdWorklogListRegistry() *CommandRegistryEntry { func CmdWorklogListRegistry(fig *figtree.FigTree, o *oreo.Client) *CommandRegistryEntry {
opts := WorklogListOptions{ opts := WorklogListOptions{
GlobalOptions: GlobalOptions{ GlobalOptions: GlobalOptions{
Template: figtree.NewStringOption("worklogs"), Template: figtree.NewStringOption("worklogs"),
@@ -19,35 +21,36 @@ func (jc *JiraCli) CmdWorklogListRegistry() *CommandRegistryEntry {
return &CommandRegistryEntry{ return &CommandRegistryEntry{
"Prints the worklog data for given issue", "Prints the worklog data for given issue",
func() error { func() error {
return jc.CmdWorklogList(&opts) return CmdWorklogList(o, &opts)
}, },
func(cmd *kingpin.CmdClause) error { func(cmd *kingpin.CmdClause) error {
return jc.CmdWorklogListUsage(cmd, &opts) LoadConfigs(cmd, fig, &opts)
return CmdWorklogListUsage(cmd, &opts)
}, },
} }
} }
func (jc *JiraCli) CmdWorklogListUsage(cmd *kingpin.CmdClause, opts *WorklogListOptions) error { func CmdWorklogListUsage(cmd *kingpin.CmdClause, opts *WorklogListOptions) error {
if err := jc.GlobalUsage(cmd, &opts.GlobalOptions); err != nil { if err := GlobalUsage(cmd, &opts.GlobalOptions); err != nil {
return err return err
} }
jc.BrowseUsage(cmd, &opts.GlobalOptions) BrowseUsage(cmd, &opts.GlobalOptions)
jc.TemplateUsage(cmd, &opts.GlobalOptions) TemplateUsage(cmd, &opts.GlobalOptions)
cmd.Arg("ISSUE", "issue id to fetch worklogs").Required().StringVar(&opts.Issue) cmd.Arg("ISSUE", "issue id to fetch worklogs").Required().StringVar(&opts.Issue)
return nil return nil
} }
// // CmdWorklogList will get worklog data for given issue and sent to the "worklogs" template // // CmdWorklogList will get worklog data for given issue and sent to the "worklogs" template
func (jc *JiraCli) CmdWorklogList(opts *WorklogListOptions) error { func CmdWorklogList(o *oreo.Client, opts *WorklogListOptions) error {
data, err := jc.GetIssueWorklog(opts.Issue) data, err := jira.GetIssueWorklog(o, opts.Endpoint.Value, opts.Issue)
if err != nil { if err != nil {
return err return err
} }
if err := jc.runTemplate(opts.Template.Value, data, nil); err != nil { if err := runTemplate(opts.Template.Value, data, nil); err != nil {
return err return err
} }
if opts.Browse.Value { if opts.Browse.Value {
return jc.CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue}) return CmdBrowse(&BrowseOptions{opts.GlobalOptions, opts.Issue})
} }
return nil return nil
} }
+6 -2
View File
@@ -8,8 +8,12 @@ import (
// https://docs.atlassian.com/jira/REST/cloud/#api/2/project-getProjectComponents // https://docs.atlassian.com/jira/REST/cloud/#api/2/project-getProjectComponents
func (j *Jira) GetProjectComponents(project string) (*jiradata.Components, error) { func (j *Jira) GetProjectComponents(project string) (*jiradata.Components, error) {
uri := fmt.Sprintf("%s/rest/api/2/project/%s/components", j.Endpoint, project) return GetProjectComponents(j.UA, j.Endpoint, project)
resp, err := j.UA.GetJSON(uri) }
func GetProjectComponents(ua HttpClient, endpoint string, project string) (*jiradata.Components, error) {
uri := fmt.Sprintf("%s/rest/api/2/project/%s/components", endpoint, project)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+6 -2
View File
@@ -70,13 +70,17 @@ func (o *SearchOptions) ProvideSearchRequest() *jiradata.SearchRequest {
// https://docs.atlassian.com/jira/REST/cloud/#api/2/search-searchUsingSearchRequest // https://docs.atlassian.com/jira/REST/cloud/#api/2/search-searchUsingSearchRequest
func (j *Jira) Search(sp SearchProvider) (*jiradata.SearchResults, error) { func (j *Jira) Search(sp SearchProvider) (*jiradata.SearchResults, error) {
return Search(j.UA, j.Endpoint, sp)
}
func Search(ua HttpClient, endpoint string, sp SearchProvider) (*jiradata.SearchResults, error) {
req := sp.ProvideSearchRequest() req := sp.ProvideSearchRequest()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/api/2/search", j.Endpoint) uri := fmt.Sprintf("%s/rest/api/2/search", endpoint)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
+18 -6
View File
@@ -26,13 +26,17 @@ func (a *AuthOptions) AuthParams() *jiradata.AuthParams {
// https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-login // https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-login
func (j *Jira) NewSession(ap AuthProvider) (*jiradata.AuthSuccess, error) { func (j *Jira) NewSession(ap AuthProvider) (*jiradata.AuthSuccess, error) {
return NewSession(j.UA, j.Endpoint, ap)
}
func NewSession(ua HttpClient, endpoint string, ap AuthProvider) (*jiradata.AuthSuccess, error) {
req := ap.ProvideAuthParams() req := ap.ProvideAuthParams()
encoded, err := json.Marshal(req) encoded, err := json.Marshal(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
uri := fmt.Sprintf("%s/rest/auth/1/session", j.Endpoint) uri := fmt.Sprintf("%s/rest/auth/1/session", endpoint)
resp, err := j.UA.Post(uri, "application/json", bytes.NewBuffer(encoded)) resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -47,8 +51,12 @@ func (j *Jira) NewSession(ap AuthProvider) (*jiradata.AuthSuccess, error) {
// https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-currentUser // https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-currentUser
func (j *Jira) GetSession() (*jiradata.CurrentUser, error) { func (j *Jira) GetSession() (*jiradata.CurrentUser, error) {
uri := fmt.Sprintf("%s/rest/auth/1/session", j.Endpoint) return GetSession(j.UA, j.Endpoint)
resp, err := j.UA.GetJSON(uri) }
func GetSession(ua HttpClient, endpoint string) (*jiradata.CurrentUser, error) {
uri := fmt.Sprintf("%s/rest/auth/1/session", endpoint)
resp, err := ua.GetJSON(uri)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -63,8 +71,12 @@ func (j *Jira) GetSession() (*jiradata.CurrentUser, error) {
// https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-logout // https://docs.atlassian.com/jira/REST/cloud/#auth/1/session-logout
func (j *Jira) DeleteSession() error { func (j *Jira) DeleteSession() error {
uri := fmt.Sprintf("%s/rest/auth/1/session", j.Endpoint) return DeleteSession(j.UA, j.Endpoint)
resp, err := j.UA.Delete(uri) }
func DeleteSession(ua HttpClient, endpoint string) error {
uri := fmt.Sprintf("%s/rest/auth/1/session", endpoint)
resp, err := ua.Delete(uri)
if err != nil { if err != nil {
return err return err
} }
+6 -1
View File
@@ -7,6 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strings" "strings"
@@ -22,6 +23,7 @@ import (
var log = logging.MustGetLogger("figtree") var log = logging.MustGetLogger("figtree")
type FigTree struct { type FigTree struct {
ConfigDir string
Defaults interface{} Defaults interface{}
EnvPrefix string EnvPrefix string
stop bool stop bool
@@ -44,7 +46,10 @@ func LoadConfig(configFile string, options interface{}) error {
func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error { func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error {
// reset from any previous config parsing runs // reset from any previous config parsing runs
f.stop = false f.stop = false
// assert options is a pointer
if f.ConfigDir != "" {
configFile = path.Join(f.ConfigDir, configFile)
}
paths := FindParentPaths(configFile) paths := FindParentPaths(configFile)
paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...) paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...)
+5 -1
View File
@@ -322,7 +322,6 @@ func (c *Client) Do(req *http.Request) (resp *http.Response, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// log any cookies sent b/c they will not be present until // log any cookies sent b/c they will not be present until
// afater we call the `Do` func // afater we call the `Do` func
if log.IsEnabledFor(logging.DEBUG) && TraceRequestBody { if log.IsEnabledFor(logging.DEBUG) && TraceRequestBody {
@@ -335,6 +334,11 @@ func (c *Client) Do(req *http.Request) (resp *http.Response, err error) {
} }
} }
if log.IsEnabledFor(logging.DEBUG) && TraceResponseBody {
out, _ := httputil.DumpResponse(resp, true)
log.Debugf("Response: %s", out)
}
err = c.saveCookies(resp) err = c.saveCookies(resp)
if err != nil { if err != nil {
return resp, err return resp, err