mirror of
https://github.com/Threnklyn/jira.git
synced 2026-06-07 13:33:32 +02:00
[#87] add various commands for interacting with epics
This commit is contained in:
+24
-1
@@ -131,6 +131,24 @@ func main() {
|
|||||||
Command: "comment",
|
Command: "comment",
|
||||||
Entry: jiracmd.CmdCommentRegistry(),
|
Entry: jiracmd.CmdCommentRegistry(),
|
||||||
},
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "epic create",
|
||||||
|
Entry: jiracmd.CmdEpicCreateRegistry(),
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "epic list",
|
||||||
|
Entry: jiracmd.CmdEpicListRegistry(),
|
||||||
|
Aliases: []string{"ls"},
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "epic add",
|
||||||
|
Entry: jiracmd.CmdEpicAddRegistry(),
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "epic remove",
|
||||||
|
Entry: jiracmd.CmdEpicRemoveRegistry(),
|
||||||
|
Aliases: []string{"rm"},
|
||||||
|
},
|
||||||
jiracli.CommandRegistry{
|
jiracli.CommandRegistry{
|
||||||
Command: "worklog list",
|
Command: "worklog list",
|
||||||
Entry: jiracmd.CmdWorklogListRegistry(),
|
Entry: jiracmd.CmdWorklogListRegistry(),
|
||||||
@@ -338,7 +356,12 @@ func main() {
|
|||||||
|
|
||||||
// checking for default usage of `jira ISSUE-123` but need to allow
|
// checking for default usage of `jira ISSUE-123` but need to allow
|
||||||
// for global options first like: `jira --user mothra ISSUE-123`
|
// for global options first like: `jira --user mothra ISSUE-123`
|
||||||
ctx, _ := app.ParseContext(os.Args[1:])
|
ctx, err := app.ParseContext(os.Args[1:])
|
||||||
|
if err != nil && ctx == nil {
|
||||||
|
// This is an internal kingpin usage error, duplicate options/commands
|
||||||
|
log.Fatalf("error: %s, ctx: %v", err, ctx)
|
||||||
|
}
|
||||||
|
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
if ctx.SelectedCommand == nil {
|
if ctx.SelectedCommand == nil {
|
||||||
next := ctx.Next()
|
next := ctx.Next()
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package jira
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/epic-getIssuesForEpic
|
||||||
|
func (j *Jira) EpicSearch(epic string, sp SearchProvider) (*jiradata.SearchResults, error) {
|
||||||
|
return EpicSearch(j.UA, j.Endpoint, epic, sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpicSearch(ua HttpClient, endpoint string, epic string, sp SearchProvider) (*jiradata.SearchResults, error) {
|
||||||
|
req := sp.ProvideSearchRequest()
|
||||||
|
// encoded, err := json.Marshal(req)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
uri, err := url.Parse(fmt.Sprintf("%s/rest/agile/1.0/epic/%s/issue", endpoint, epic))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params := url.Values{}
|
||||||
|
if len(req.Fields) > 0 {
|
||||||
|
params.Add("fields", strings.Join(req.Fields, ","))
|
||||||
|
}
|
||||||
|
if req.JQL != "" {
|
||||||
|
params.Add("jql", req.JQL)
|
||||||
|
}
|
||||||
|
if req.MaxResults != 0 {
|
||||||
|
params.Add("maxResults", fmt.Sprintf("%d", req.MaxResults))
|
||||||
|
}
|
||||||
|
if req.StartAt != 0 {
|
||||||
|
params.Add("startAt", fmt.Sprintf("%d", req.StartAt))
|
||||||
|
}
|
||||||
|
if req.ValidateQuery != "" {
|
||||||
|
params.Add("validateQuery", req.ValidateQuery)
|
||||||
|
}
|
||||||
|
uri.RawQuery = params.Encode()
|
||||||
|
|
||||||
|
resp, err := ua.Do(oreo.RequestBuilder(uri).WithHeader("Accept", "application/json").Build())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 200 {
|
||||||
|
results := &jiradata.SearchResults{}
|
||||||
|
return results, readJSON(resp.Body, results)
|
||||||
|
}
|
||||||
|
return nil, responseError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type EpicIssuesProvider interface {
|
||||||
|
ProvideEpicIssues() *jiradata.EpicIssues
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/epic-moveIssuesToEpic
|
||||||
|
func (j *Jira) EpicAddIssues(epic string, eip EpicIssuesProvider) error {
|
||||||
|
return EpicAddIssues(j.UA, j.Endpoint, epic, eip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpicAddIssues(ua HttpClient, endpoint string, epic string, eip EpicIssuesProvider) error {
|
||||||
|
req := eip.ProvideEpicIssues()
|
||||||
|
encoded, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/agile/1.0/epic/%s/issue", endpoint, epic)
|
||||||
|
resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return responseError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/epic-removeIssuesFromEpic
|
||||||
|
func (j *Jira) EpicRemoveIssues(eip EpicIssuesProvider) error {
|
||||||
|
return EpicRemoveIssues(j.UA, j.Endpoint, eip)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EpicRemoveIssues(ua HttpClient, endpoint string, eip EpicIssuesProvider) error {
|
||||||
|
req := eip.ProvideEpicIssues()
|
||||||
|
encoded, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri := fmt.Sprintf("%s/rest/agile/1.0/epic/none/issue", endpoint)
|
||||||
|
resp, err := ua.Post(uri, "application/json", bytes.NewBuffer(encoded))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return responseError(resp)
|
||||||
|
}
|
||||||
+28
-1
@@ -193,7 +193,7 @@ func translateOptions(opts interface{}) (interface{}, error) {
|
|||||||
yaml.DefaultMapType = reflect.TypeOf(map[string]interface{}{})
|
yaml.DefaultMapType = reflect.TypeOf(map[string]interface{}{})
|
||||||
yaml.IfaceType = yaml.DefaultMapType.Elem()
|
yaml.IfaceType = yaml.DefaultMapType.Elem()
|
||||||
|
|
||||||
var rawData map[string]interface{}
|
var rawData interface{}
|
||||||
if err := yaml.Unmarshal(jsonData, &rawData); err != nil {
|
if err := yaml.Unmarshal(jsonData, &rawData); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -236,6 +236,8 @@ var AllTemplates = map[string]string{
|
|||||||
"debug": defaultDebugTemplate,
|
"debug": defaultDebugTemplate,
|
||||||
"edit": defaultEditTemplate,
|
"edit": defaultEditTemplate,
|
||||||
"editmeta": defaultDebugTemplate,
|
"editmeta": defaultDebugTemplate,
|
||||||
|
"epic-create": defaultEpicCreateTemplate,
|
||||||
|
"epic-list": defaultTableTemplate,
|
||||||
"fields": defaultDebugTemplate,
|
"fields": defaultDebugTemplate,
|
||||||
"issuelinktypes": defaultDebugTemplate,
|
"issuelinktypes": defaultDebugTemplate,
|
||||||
"issuetypes": defaultIssuetypesTemplate,
|
"issuetypes": defaultIssuetypesTemplate,
|
||||||
@@ -387,6 +389,31 @@ fields:
|
|||||||
- name: {{.}}{{end}}
|
- name: {{.}}{{end}}
|
||||||
- name:{{end}}`
|
- name:{{end}}`
|
||||||
|
|
||||||
|
const defaultEpicCreateTemplate = `{{/* epic create template */ -}}
|
||||||
|
fields:
|
||||||
|
project:
|
||||||
|
key: {{ or .overrides.project "" }}
|
||||||
|
# Epic Name
|
||||||
|
customfield_10120: {{ or (index .overrides "epic-name") "" }}
|
||||||
|
summary: >-
|
||||||
|
{{ or .overrides.summary "" }}{{if .meta.fields.priority.allowedValues}}
|
||||||
|
priority: # Values: {{ range .meta.fields.priority.allowedValues }}{{.name}}, {{end}}
|
||||||
|
name: {{ or .overrides.priority ""}}{{end}}{{if .meta.fields.components.allowedValues}}
|
||||||
|
components: # Values: {{ range .meta.fields.components.allowedValues }}{{.name}}, {{end}}{{ range split "," (or .overrides.components "")}}
|
||||||
|
- name: {{ . }}{{end}}{{end}}
|
||||||
|
description: |~
|
||||||
|
{{ or .overrides.description "" | indent 4 }}{{if .meta.fields.assignee}}
|
||||||
|
assignee:
|
||||||
|
name: {{ or .overrides.assignee "" }}{{end}}{{if .meta.fields.reporter}}
|
||||||
|
reporter:
|
||||||
|
name: {{ or .overrides.reporter .overrides.user }}{{end}}{{if .meta.fields.customfield_10110}}
|
||||||
|
# watchers
|
||||||
|
customfield_10110: {{ range split "," (or .overrides.watchers "")}}
|
||||||
|
- name: {{.}}{{end}}
|
||||||
|
- name:{{end}}
|
||||||
|
issuetype:
|
||||||
|
name: Epic`
|
||||||
|
|
||||||
const defaultSubtaskTemplate = `{{/* create subtask template */ -}}
|
const defaultSubtaskTemplate = `{{/* create subtask template */ -}}
|
||||||
fields:
|
fields:
|
||||||
project:
|
project:
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EpicAddOptions struct {
|
||||||
|
jiradata.EpicIssues `yaml:",inline" json:",inline" figtree:",inline"`
|
||||||
|
Epic string `yaml:"epic,omitempty" json:"epic,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicAddRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := EpicAddOptions{}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Add issues to Epic",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdEpicAddUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdEpicAdd(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicAddUsage(cmd *kingpin.CmdClause, opts *EpicAddOptions) error {
|
||||||
|
cmd.Arg("EPIC", "Epic Key or ID to add issues to").Required().StringVar(&opts.Epic)
|
||||||
|
cmd.Arg("ISSUE", "Issues to add to epic").Required().StringsVar(&opts.Issues)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicAdd(o *oreo.Client, globals *jiracli.GlobalOptions, opts *EpicAddOptions) error {
|
||||||
|
if err := jira.EpicAddIssues(o, globals.Endpoint.Value, opts.Epic, &opts.EpicIssues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !globals.Quiet.Value {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", opts.Epic, globals.Endpoint.Value, opts.Epic)
|
||||||
|
for _, issue := range opts.Issues {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", issue, globals.Endpoint.Value, issue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CmdEpicCreateRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := CreateOptions{
|
||||||
|
CommonOptions: jiracli.CommonOptions{
|
||||||
|
Template: figtree.NewStringOption("epic-create"),
|
||||||
|
},
|
||||||
|
Overrides: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Create Epic",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdEpicCreateUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdCreate(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicCreateUsage(cmd *kingpin.CmdClause, opts *CreateOptions) error {
|
||||||
|
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
|
||||||
|
jiracli.EditorUsage(cmd, &opts.CommonOptions)
|
||||||
|
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
|
||||||
|
cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
|
||||||
|
cmd.Flag("project", "project to create epic in").Short('p').StringVar(&opts.Project)
|
||||||
|
cmd.Flag("epic-name", "Epic Name").Short('n').PreAction(func(ctx *kingpin.ParseContext) error {
|
||||||
|
opts.Overrides["epic-name"] = jiracli.FlagValue(ctx, "epic-name")
|
||||||
|
return nil
|
||||||
|
}).String()
|
||||||
|
cmd.Flag("comment", "Comment message for epic").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
|
||||||
|
opts.Overrides["comment"] = jiracli.FlagValue(ctx, "comment")
|
||||||
|
return nil
|
||||||
|
}).String()
|
||||||
|
cmd.Flag("override", "Set epic property").Short('o').StringMapVar(&opts.Overrides)
|
||||||
|
cmd.Flag("saveFile", "Write epic as yaml to file").StringVar(&opts.SaveFile)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EpicListOptions struct {
|
||||||
|
ListOptions `yaml:",inline" json:",inline" figtree:",inline"`
|
||||||
|
Epic string `yaml:"epic,omitempty" json:"epic,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicListRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := EpicListOptions{
|
||||||
|
ListOptions: ListOptions{
|
||||||
|
CommonOptions: jiracli.CommonOptions{
|
||||||
|
Template: figtree.NewStringOption("epic-list"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Prints list of issues for an epic with optional search criteria",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
if opts.MaxResults == 0 {
|
||||||
|
opts.MaxResults = 500
|
||||||
|
}
|
||||||
|
if opts.QueryFields == "" {
|
||||||
|
opts.QueryFields = "assignee,created,priority,reporter,status,summary,updated"
|
||||||
|
}
|
||||||
|
if opts.Sort == "" {
|
||||||
|
opts.Sort = "priority asc, key"
|
||||||
|
}
|
||||||
|
return CmdEpicListUsage(cmd, &opts, fig)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdEpicList(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicListUsage(cmd *kingpin.CmdClause, opts *EpicListOptions, fig *figtree.FigTree) error {
|
||||||
|
CmdListUsage(cmd, &opts.ListOptions, fig)
|
||||||
|
cmd.Arg("EPIC", "Epic Key or ID to list").Required().StringVar(&opts.Epic)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicList(o *oreo.Client, globals *jiracli.GlobalOptions, opts *EpicListOptions) error {
|
||||||
|
data, err := jira.EpicSearch(o, globals.Endpoint.Value, opts.Epic, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return opts.PrintTemplate(data)
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EpicRemoveOptions struct {
|
||||||
|
jiradata.EpicIssues `yaml:",inline" json:",inline" figtree:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicRemoveRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := EpicRemoveOptions{}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Remove issues from Epic",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdEpicRemoveUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdEpicRemove(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicRemoveUsage(cmd *kingpin.CmdClause, opts *EpicRemoveOptions) error {
|
||||||
|
cmd.Arg("ISSUE", "Issues to remove from any epic").Required().StringsVar(&opts.Issues)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdEpicRemove(o *oreo.Client, globals *jiracli.GlobalOptions, opts *EpicRemoveOptions) error {
|
||||||
|
if err := jira.EpicRemoveIssues(o, globals.Endpoint.Value, &opts.EpicIssues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !globals.Quiet.Value {
|
||||||
|
for _, issue := range opts.Issues {
|
||||||
|
fmt.Printf("OK %s %s/browse/%s\n", issue, globals.Endpoint.Value, issue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
type EpicIssues struct {
|
||||||
|
Issues []string `json:"issues,omitempty" yaml:"issues,omitempty"`
|
||||||
|
}
|
||||||
@@ -25,3 +25,7 @@ func (c *Comment) ProvideComment() *Comment {
|
|||||||
func (c *Component) ProvideComponent() *Component {
|
func (c *Component) ProvideComponent() *Component {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EpicIssues) ProvideEpicIssues() *EpicIssues {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|||||||
Executable
+121
@@ -0,0 +1,121 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
|
||||||
|
cd $(dirname $0)
|
||||||
|
jira="../jira"
|
||||||
|
. env.sh
|
||||||
|
|
||||||
|
PLAN 22
|
||||||
|
|
||||||
|
# reset login
|
||||||
|
RUNS $jira logout
|
||||||
|
RUNS $jira login
|
||||||
|
|
||||||
|
# cleanup from previous failed test executions
|
||||||
|
($jira ls --project BASIC | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Create an epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic create --project BASIC -o summary="Totally Epic" -o description=description --epic-name "Basic Epic" --noedit --saveFile issue.props
|
||||||
|
epic=$(awk '/issue/{print $2}' issue.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $epic $ENDPOINT/browse/$epic
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Create issues we can assign to epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira create --project BASIC -o summary="summary" -o description=description --noedit --saveFile issue.props
|
||||||
|
issue1=$(awk '/issue/{print $2}' issue.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $issue1 $ENDPOINT/browse/$issue1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUNS $jira create --project BASIC -o summary="summary" -o description=description --noedit --saveFile issue.props
|
||||||
|
issue2=$(awk '/issue/{print $2}' issue.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $issue2 $ENDPOINT/browse/$issue2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## List the issues for the epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic list $epic
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Add issues to an epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic add $epic $issue1 $issue2
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
OK $epic $ENDPOINT/browse/$epic
|
||||||
|
OK $issue1 $ENDPOINT/browse/$issue1
|
||||||
|
OK $issue2 $ENDPOINT/browse/$issue2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## List the issues for the epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic list $epic
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| $(printf %-14s $issue1) | summary | Medium | To Do | a minute | gojira | gojira |
|
||||||
|
| $(printf %-14s $issue2) | summary | Medium | To Do | a minute | gojira | gojira |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Remove an issue from an Epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic remove $issue1
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
OK $issue1 $ENDPOINT/browse/$issue1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## List the issues for the epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic list $epic
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| $(printf %-14s $issue2) | summary | Medium | To Do | a minute | gojira | gojira |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Remove last issue from an Epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic remove $issue2
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
OK $issue2 $ENDPOINT/browse/$issue2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## List the issues for the epic
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira epic list $epic
|
||||||
|
|
||||||
|
DIFF<<EOF
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
Reference in New Issue
Block a user