mirror of
https://github.com/Threnklyn/jira.git
synced 2026-05-31 10:18:29 +02:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e21f18e987 | |||
| 96bbbd7ce3 | |||
| 3e8b9bd9f5 | |||
| 8fe0d98d54 | |||
| 1a3eaf340c | |||
| 96b4658dcb | |||
| c9d8dfbe55 | |||
| 238e16fc09 | |||
| 22a354ce42 | |||
| d9736919bb | |||
| 3c16e1754a | |||
| 650bc4b50d | |||
| b1c9bf5ae5 | |||
| 66eb7bff38 | |||
| abc82b909e | |||
| dabf4cf034 | |||
| 79a6381307 | |||
| 893454fc69 | |||
| d5b9631cf4 |
@@ -2,4 +2,9 @@ jira
|
|||||||
schemas/*.json
|
schemas/*.json
|
||||||
t/.gnupg/random_seed
|
t/.gnupg/random_seed
|
||||||
t/issue.props
|
t/issue.props
|
||||||
|
t/attach.props
|
||||||
|
t/garbage.bin
|
||||||
|
t/attach1.txt
|
||||||
|
t/binary.out
|
||||||
|
t/foobar.bin
|
||||||
dist
|
dist
|
||||||
@@ -1,5 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.9 - 2017-09-17
|
||||||
|
|
||||||
|
* need issuetype to use the default list table template now [Cory Bennett] [[3e8b9bd](https://github.com/Netflix-Skunkworks/go-jira/commit/3e8b9bd)]
|
||||||
|
* [[#102](https://github.com/Netflix-Skunkworks/go-jira/issues/102)] add issuetype into the default queryfields and add it to the default `table` list template [Cory Bennett] [[c9d8dfb](https://github.com/Netflix-Skunkworks/go-jira/commit/c9d8dfb)]
|
||||||
|
|
||||||
|
## 1.0.8 - 2017-09-17
|
||||||
|
|
||||||
|
* [[#100](https://github.com/Netflix-Skunkworks/go-jira/issues/100)] add support for posting, fetching, listing and removing attachments [Cory Bennett] [[66eb7bf](https://github.com/Netflix-Skunkworks/go-jira/commit/66eb7bf)]
|
||||||
|
|
||||||
|
## 1.0.7 - 2017-09-15
|
||||||
|
|
||||||
|
* [[#87](https://github.com/Netflix-Skunkworks/go-jira/issues/87)] add various commands for interacting with epics [Cory Bennett] [[893454f](https://github.com/Netflix-Skunkworks/go-jira/commit/893454f)]
|
||||||
|
|
||||||
## 1.0.6 - 2017-09-13
|
## 1.0.6 - 2017-09-13
|
||||||
|
|
||||||
* tweaks for templates in named queries to work better [Cory Bennett] [[00cba79](https://github.com/Netflix-Skunkworks/go-jira/commit/00cba79)]
|
* tweaks for templates in named queries to work better [Cory Bennett] [[00cba79](https://github.com/Netflix-Skunkworks/go-jira/commit/00cba79)]
|
||||||
|
|||||||
@@ -66,8 +66,13 @@ update-changelog:
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
release:
|
release:
|
||||||
git commit -m "Updated Changelog" CHANGELOG.md; \
|
perl -pi -e 'undef $$/; s/\n```\nusage.*```//sg' README.md
|
||||||
git commit -m "version bump" jira.go
|
echo '```' >> README.md
|
||||||
|
./jira --help-long >> README.md || true
|
||||||
|
echo '```' >> README.md
|
||||||
|
git diff --exit-code --quiet README.md || git commit -m "Updated Usage" README.md
|
||||||
|
git commit -m "Updated Changelog" CHANGELOG.md
|
||||||
|
git commit -m "version bump" jira.go
|
||||||
git tag v$(NEWVER)
|
git tag v$(NEWVER)
|
||||||
git push --tags
|
git push --tags
|
||||||
|
|
||||||
|
|||||||
@@ -429,14 +429,17 @@ Commands:
|
|||||||
Prints list of issues for given search criteria
|
Prints list of issues for given search criteria
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
-a, --assignee=ASSIGNEE User assigned the issue
|
-a, --assignee=ASSIGNEE User assigned the issue
|
||||||
-c, --component=COMPONENT Component to search for
|
-c, --component=COMPONENT Component to search for
|
||||||
-i, --issuetype=ISSUETYPE Issue type to search for
|
-i, --issuetype=ISSUETYPE Issue type to search for
|
||||||
-l, --limit=LIMIT Maximum number of results to return in search
|
-l, --limit=LIMIT Maximum number of results to return in search
|
||||||
-p, --project=PROJECT Project to search for
|
-p, --project=PROJECT Project to search for
|
||||||
|
-n, --named-query=NAMED-QUERY The name of a query in the `queries` configuration
|
||||||
-q, --query=QUERY Jira Query Language (JQL) expression for the search
|
-q, --query=QUERY Jira Query Language (JQL) expression for the search
|
||||||
-f, --queryfields=QUERYFIELDS Fields that are used in "list" template
|
-f, --queryfields=QUERYFIELDS Fields that are used in "list" template
|
||||||
-r, --reporter=REPORTER Reporter to search for
|
-r, --reporter=REPORTER Reporter to search for
|
||||||
|
-S, --status=STATUS Filter on issue status
|
||||||
-s, --sort=SORT Sort order to return
|
-s, --sort=SORT Sort order to return
|
||||||
-w, --watcher=WATCHER Watcher to search for
|
-w, --watcher=WATCHER Watcher to search for
|
||||||
|
|
||||||
@@ -445,6 +448,7 @@ Commands:
|
|||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
--expand=EXPAND ... field to expand for the issue
|
--expand=EXPAND ... field to expand for the issue
|
||||||
--field=FIELD ... field to return for the issue
|
--field=FIELD ... field to return for the issue
|
||||||
--property=PROPERTY ... property to return for issue
|
--property=PROPERTY ... property to return for issue
|
||||||
@@ -465,13 +469,14 @@ Commands:
|
|||||||
edit [<flags>] [<ISSUE>]
|
edit [<flags>] [<ISSUE>]
|
||||||
Edit issue details
|
Edit issue details
|
||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
--editor=EDITOR Editor to use
|
--editor=EDITOR Editor to use
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
--noedit Disable opening the editor
|
--noedit Disable opening the editor
|
||||||
-q, --query=QUERY Jira Query Language (JQL) expression for the search to edit multiple issues
|
-n, --named-query=NAMED-QUERY The name of a query in the `queries` configuration
|
||||||
-m, --comment=COMMENT Comment message for issue
|
-q, --query=QUERY Jira Query Language (JQL) expression for the search to edit multiple issues
|
||||||
-o, --override=OVERRIDE ... Set issue property
|
-m, --comment=COMMENT Comment message for issue
|
||||||
|
-o, --override=OVERRIDE ... Set issue property
|
||||||
|
|
||||||
comment [<flags>] [<ISSUE>]
|
comment [<flags>] [<ISSUE>]
|
||||||
Add comment to issue
|
Add comment to issue
|
||||||
@@ -482,11 +487,51 @@ Commands:
|
|||||||
--noedit Disable opening the editor
|
--noedit Disable opening the editor
|
||||||
-m, --comment=COMMENT Comment message for issue
|
-m, --comment=COMMENT Comment message for issue
|
||||||
|
|
||||||
|
epic create [<flags>]
|
||||||
|
Create Epic
|
||||||
|
|
||||||
|
-b, --browse Open issue(s) in browser after operation
|
||||||
|
--editor=EDITOR Editor to use
|
||||||
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--noedit Disable opening the editor
|
||||||
|
-p, --project=PROJECT project to create epic in
|
||||||
|
-n, --epic-name=EPIC-NAME Epic Name
|
||||||
|
-m, --comment=COMMENT Comment message for epic
|
||||||
|
-o, --override=OVERRIDE ... Set epic property
|
||||||
|
--saveFile=SAVEFILE Write epic as yaml to file
|
||||||
|
|
||||||
|
epic list [<flags>] <EPIC>
|
||||||
|
Prints list of issues for an epic with optional search criteria
|
||||||
|
|
||||||
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
-a, --assignee=ASSIGNEE User assigned the issue
|
||||||
|
-c, --component=COMPONENT Component to search for
|
||||||
|
-i, --issuetype=ISSUETYPE Issue type to search for
|
||||||
|
-l, --limit=LIMIT Maximum number of results to return in search
|
||||||
|
-p, --project=PROJECT Project to search for
|
||||||
|
-n, --named-query=NAMED-QUERY The name of a query in the `queries` configuration
|
||||||
|
-q, --query=QUERY Jira Query Language (JQL) expression for the search
|
||||||
|
-f, --queryfields=QUERYFIELDS Fields that are used in "list" template
|
||||||
|
-r, --reporter=REPORTER Reporter to search for
|
||||||
|
-S, --status=STATUS Filter on issue status
|
||||||
|
-s, --sort=SORT Sort order to return
|
||||||
|
-w, --watcher=WATCHER Watcher to search for
|
||||||
|
|
||||||
|
epic add <EPIC> <ISSUE>...
|
||||||
|
Add issues to Epic
|
||||||
|
|
||||||
|
|
||||||
|
epic remove <ISSUE>...
|
||||||
|
Remove issues from Epic
|
||||||
|
|
||||||
|
|
||||||
worklog list [<flags>] <ISSUE>
|
worklog list [<flags>] <ISSUE>
|
||||||
Prints the worklog data for given issue
|
Prints the worklog data for given issue
|
||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
worklog add [<flags>] <ISSUE>
|
worklog add [<flags>] <ISSUE>
|
||||||
Add a worklog to an issue
|
Add a worklog to an issue
|
||||||
@@ -497,16 +542,19 @@ Commands:
|
|||||||
--noedit Disable opening the editor
|
--noedit Disable opening the editor
|
||||||
-m, --comment=COMMENT Comment message for worklog
|
-m, --comment=COMMENT Comment message for worklog
|
||||||
-T, --time-spent=TIME-SPENT Time spent working on issue
|
-T, --time-spent=TIME-SPENT Time spent working on issue
|
||||||
|
-S, --started=STARTED Time you started work
|
||||||
|
|
||||||
fields [<flags>]
|
fields [<flags>]
|
||||||
Prints all fields, both System and Custom
|
Prints all fields, both System and Custom
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
createmeta [<flags>]
|
createmeta [<flags>]
|
||||||
View 'create' metadata
|
View 'create' metadata
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
-p, --project=PROJECT project to fetch create metadata
|
-p, --project=PROJECT project to fetch create metadata
|
||||||
-i, --issuetype=ISSUETYPE issuetype in project to fetch create metadata
|
-i, --issuetype=ISSUETYPE issuetype in project to fetch create metadata
|
||||||
|
|
||||||
@@ -515,6 +563,7 @@ Commands:
|
|||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
subtask [<flags>] [<ISSUE>]
|
subtask [<flags>] [<ISSUE>]
|
||||||
Subtask issue
|
Subtask issue
|
||||||
@@ -555,6 +604,7 @@ Commands:
|
|||||||
Show the issue link types
|
Show the issue link types
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
transition [<flags>] <TRANSITION> <ISSUE>
|
transition [<flags>] <TRANSITION> <ISSUE>
|
||||||
Transition issue to given state
|
Transition issue to given state
|
||||||
@@ -570,12 +620,14 @@ Commands:
|
|||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
transmeta [<flags>] <ISSUE>
|
transmeta [<flags>] <ISSUE>
|
||||||
List valid issue transitions
|
List valid issue transitions
|
||||||
|
|
||||||
-b, --browse Open issue(s) in browser after operation
|
-b, --browse Open issue(s) in browser after operation
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
|
||||||
close [<flags>] <ISSUE>
|
close [<flags>] <ISSUE>
|
||||||
Transition issue to close state
|
Transition issue to close state
|
||||||
@@ -732,14 +784,38 @@ Commands:
|
|||||||
Show components for a project
|
Show components for a project
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
-p, --project=PROJECT project to list components
|
-p, --project=PROJECT project to list components
|
||||||
|
|
||||||
issuetypes [<flags>]
|
issuetypes [<flags>]
|
||||||
Show issue types for a project
|
Show issue types for a project
|
||||||
|
|
||||||
-t, --template=TEMPLATE Template to use for output
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
-p, --project=PROJECT project to list issueTypes
|
-p, --project=PROJECT project to list issueTypes
|
||||||
|
|
||||||
|
attach create [<flags>] <ISSUE> [<ATTACHMENT>]
|
||||||
|
Attach file to issue
|
||||||
|
|
||||||
|
-b, --browse Open issue(s) in browser after operation
|
||||||
|
--saveFile=SAVEFILE Write attachment information as yaml to file
|
||||||
|
-f, --filename=FILENAME Filename to use for attachment
|
||||||
|
|
||||||
|
attach list [<flags>] <ISSUE>
|
||||||
|
Prints issue details
|
||||||
|
|
||||||
|
-b, --browse Open issue(s) in browser after operation
|
||||||
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
|
||||||
|
attach get [<flags>] [<ATTACHMENT-ID>]
|
||||||
|
Fetch attachment
|
||||||
|
|
||||||
|
-o, --output=OUTPUT Write attachment to specified file name, '-' for stdout
|
||||||
|
|
||||||
|
attach remove [<ATTACHMENT-ID>]
|
||||||
|
Delete attachment
|
||||||
|
|
||||||
|
|
||||||
export-templates [<flags>]
|
export-templates [<flags>]
|
||||||
Export templates for customizations
|
Export templates for customizations
|
||||||
|
|
||||||
@@ -759,5 +835,9 @@ Commands:
|
|||||||
request [<flags>] <API> [<JSON>]
|
request [<flags>] <API> [<JSON>]
|
||||||
Open issue in requestr
|
Open issue in requestr
|
||||||
|
|
||||||
-M, --method=METHOD HTTP request method to use
|
-t, --template=TEMPLATE Template to use for output
|
||||||
|
--gjq=GJQ GJSON Query to filter output, see https://goo.gl/iaYwJ5
|
||||||
|
-M, --method=METHOD HTTP request method to use
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package jira
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira/REST/cloud/#api/2/attachment-getAttachment
|
||||||
|
func (j *Jira) GetAttachment(id string) (*jiradata.Attachment, error) {
|
||||||
|
return GetAttachment(j.UA, j.Endpoint, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAttachment(ua HttpClient, endpoint string, id string) (*jiradata.Attachment, error) {
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/attachment/%s", endpoint, id)
|
||||||
|
resp, err := ua.GetJSON(uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 200 {
|
||||||
|
results := &jiradata.Attachment{}
|
||||||
|
return results, readJSON(resp.Body, results)
|
||||||
|
}
|
||||||
|
return nil, responseError(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira/REST/cloud/#api/2/attachment-removeAttachment
|
||||||
|
func (j *Jira) RemoveAttachment(id string) error {
|
||||||
|
return RemoveAttachment(j.UA, j.Endpoint, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveAttachment(ua HttpClient, endpoint string, id string) error {
|
||||||
|
uri := fmt.Sprintf("%s/rest/api/2/attachment/%s", endpoint, id)
|
||||||
|
resp, err := ua.Delete(uri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return responseError(resp)
|
||||||
|
}
|
||||||
+42
-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(),
|
||||||
@@ -277,6 +295,24 @@ func main() {
|
|||||||
Command: "issuetypes",
|
Command: "issuetypes",
|
||||||
Entry: jiracmd.CmdIssueTypesRegistry(),
|
Entry: jiracmd.CmdIssueTypesRegistry(),
|
||||||
},
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "attach create",
|
||||||
|
Entry: jiracmd.CmdAttachCreateRegistry(),
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "attach list",
|
||||||
|
Entry: jiracmd.CmdAttachListRegistry(),
|
||||||
|
Aliases: []string{"ls"},
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "attach get",
|
||||||
|
Entry: jiracmd.CmdAttachGetRegistry(),
|
||||||
|
},
|
||||||
|
jiracli.CommandRegistry{
|
||||||
|
Command: "attach remove",
|
||||||
|
Entry: jiracmd.CmdAttachRemoveRegistry(),
|
||||||
|
Aliases: []string{"rm"},
|
||||||
|
},
|
||||||
jiracli.CommandRegistry{
|
jiracli.CommandRegistry{
|
||||||
Command: "export-templates",
|
Command: "export-templates",
|
||||||
Entry: jiracmd.CmdExportTemplatesRegistry(),
|
Entry: jiracmd.CmdExportTemplatesRegistry(),
|
||||||
@@ -338,7 +374,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)
|
||||||
|
}
|
||||||
@@ -4,8 +4,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
|
||||||
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -533,3 +538,50 @@ func IssueAssign(ua HttpClient, endpoint string, issue, name string) error {
|
|||||||
}
|
}
|
||||||
return responseError(resp)
|
return responseError(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://docs.atlassian.com/jira/REST/cloud/#api/2/issue/{issueIdOrKey}/attachments-addAttachment
|
||||||
|
func (j *Jira) IssueAttachFile(issue, filename string, contents io.Reader) (*jiradata.ListOfAttachment, error) {
|
||||||
|
return IssueAttachFile(j.UA, j.Endpoint, issue, filename, contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IssueAttachFile(ua HttpClient, endpoint string, issue, filename string, contents io.Reader) (*jiradata.ListOfAttachment, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := multipart.NewWriter(&buf)
|
||||||
|
formFile, err := w.CreateFormFile("file", filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(formFile, contents)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
uri, err := url.Parse(fmt.Sprintf("%s/rest/api/2/issue/%s/attachments", endpoint, issue))
|
||||||
|
req := oreo.RequestBuilder(uri).WithMethod("POST").WithHeader(
|
||||||
|
"X-Atlassian-Token", "no-check",
|
||||||
|
).WithHeader(
|
||||||
|
"Accept", "application/json",
|
||||||
|
).WithContentType(w.FormDataContentType()).WithBody(&buf).Build()
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
resp, err := ua.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == 200 {
|
||||||
|
// FIXME move this to a test, and run go tests as part of our regression
|
||||||
|
if false {
|
||||||
|
// this is because schema is wrong, defaults to type `int`, so we manually change it
|
||||||
|
// to `string`. If the jiradata is regenerated we need to manually make the change
|
||||||
|
// again.
|
||||||
|
log.Debugf("Assert Attachment.ID is a string, rather than int: %v", &jiradata.Attachment{
|
||||||
|
ID: jiradata.IntOrString(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
results := jiradata.ListOfAttachment{}
|
||||||
|
return &results, readJSON(resp.Body, &results)
|
||||||
|
}
|
||||||
|
return nil, responseError(resp)
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
var log = logging.MustGetLogger("jira")
|
var log = logging.MustGetLogger("jira")
|
||||||
|
|
||||||
const VERSION = "1.0.6"
|
const VERSION = "1.0.9"
|
||||||
|
|
||||||
type Jira struct {
|
type Jira struct {
|
||||||
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
|
||||||
|
|||||||
+53
-15
@@ -160,7 +160,8 @@ func TemplateProcessor() *template.Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ConfigTemplate(fig *figtree.FigTree, template, command string, opts interface{}) (string, error) {
|
func ConfigTemplate(fig *figtree.FigTree, template, command string, opts interface{}) (string, error) {
|
||||||
tmp, err := translateOptions(opts)
|
var tmp interface{}
|
||||||
|
err := ConvertType(opts, &tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -178,11 +179,11 @@ func ConfigTemplate(fig *figtree.FigTree, template, command string, opts interfa
|
|||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateOptions(opts interface{}) (interface{}, error) {
|
func ConvertType(input interface{}, output interface{}) error {
|
||||||
// HACK HACK HACK: convert data formats to json for backwards compatibilty with templates
|
// HACK HACK HACK: convert data formats to json for backwards compatibilty with templates
|
||||||
jsonData, err := json.Marshal(opts)
|
jsonData, err := json.Marshal(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(mapType, iface reflect.Type) {
|
defer func(mapType, iface reflect.Type) {
|
||||||
@@ -193,11 +194,10 @@ 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{}
|
if err := yaml.Unmarshal(jsonData, output); err != nil {
|
||||||
if err := yaml.Unmarshal(jsonData, &rawData); err != nil {
|
return err
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return &rawData, nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +212,8 @@ func RunTemplate(templateName string, data interface{}, out io.Writer) error {
|
|||||||
out = os.Stdout
|
out = os.Stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
rawData, err := translateOptions(data)
|
var rawData interface{}
|
||||||
|
err = ConvertType(data, &rawData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -228,6 +229,7 @@ func RunTemplate(templateName string, data interface{}, out io.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var AllTemplates = map[string]string{
|
var AllTemplates = map[string]string{
|
||||||
|
"attach-list": defaultAttachListTemplate,
|
||||||
"comment": defaultCommentTemplate,
|
"comment": defaultCommentTemplate,
|
||||||
"component-add": defaultComponentAddTemplate,
|
"component-add": defaultComponentAddTemplate,
|
||||||
"components": defaultComponentsTemplate,
|
"components": defaultComponentsTemplate,
|
||||||
@@ -236,6 +238,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,
|
||||||
@@ -257,14 +261,23 @@ const defaultDebugTemplate = "{{ . | toJson}}\n"
|
|||||||
const defaultListTemplate = "{{ range .issues }}{{ .key | append \":\" | printf \"%-12s\"}} {{ .fields.summary }}\n{{ end }}"
|
const defaultListTemplate = "{{ range .issues }}{{ .key | append \":\" | printf \"%-12s\"}} {{ .fields.summary }}\n{{ end }}"
|
||||||
|
|
||||||
const defaultTableTemplate = `{{/* table template */ -}}
|
const defaultTableTemplate = `{{/* table template */ -}}
|
||||||
{{$w := sub termWidth 92 -}}
|
{{$w := sub termWidth 107 -}}
|
||||||
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
| {{ "Issue" | printf "%-14s" }} | {{ "Summary" | printf (printf "%%-%ds" (sub $w 2)) }} | {{ "Priority" | printf "%-12s" }} | {{ "Status" | printf "%-12s" }} | {{ "Age" | printf "%-10s" }} | {{ "Reporter" | printf "%-12s" }} | {{ "Assignee" | printf "%-12s" }} |
|
| {{ "Issue" | printf "%-14s" }} | {{ "Summary" | printf (printf "%%-%ds" (sub $w 2)) }} | {{ "Type" | printf "%-12s"}} | {{ "Priority" | printf "%-12s" }} | {{ "Status" | printf "%-12s" }} | {{ "Age" | printf "%-10s" }} | {{ "Reporter" | printf "%-12s" }} | {{ "Assignee" | printf "%-12s" }} |
|
||||||
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
{{ range .issues -}}
|
{{ range .issues -}}
|
||||||
| {{ .key | printf "%-14s"}} | {{ .fields.summary | abbrev (sub $w 2) | printf (printf "%%-%ds" (sub $w 2)) }} | {{.fields.priority.name | printf "%-12s" }} | {{.fields.status.name | printf "%-12s" }} | {{.fields.created | age | printf "%-10s" }} | {{if .fields.reporter}}{{ .fields.reporter.name | printf "%-12s"}}{{else}}<unassigned>{{end}} | {{if .fields.assignee }}{{.fields.assignee.name | printf "%-12s" }}{{else}}<unassigned>{{end}} |
|
| {{ .key | printf "%-14s"}} | {{ .fields.summary | abbrev (sub $w 2) | printf (printf "%%-%ds" (sub $w 2)) }} | {{.fields.issuetype.name | printf "%-12s" }} | {{.fields.priority.name | printf "%-12s" }} | {{.fields.status.name | printf "%-12s" }} | {{.fields.created | age | printf "%-10s" }} | {{if .fields.reporter}}{{ .fields.reporter.name | printf "%-12s"}}{{else}}<unassigned>{{end}} | {{if .fields.assignee }}{{.fields.assignee.name | printf "%-12s" }}{{else}}<unassigned>{{end}} |
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
+{{ "-" | rep 16 }}+{{ "-" | rep $w }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
|
`
|
||||||
|
const defaultAttachListTemplate = `{{/* table template */ -}}
|
||||||
|
+{{ "-" | rep 12 }}+{{ "-" | rep 30 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
|
| {{printf "%-10s" "id"}} | {{printf "%-28s" "filename"}} | {{printf "%-10s" "bytes"}} | {{printf "%-12s" "user"}} | {{printf "%-12s" "created"}} |
|
||||||
|
+{{ "-" | rep 12 }}+{{ "-" | rep 30 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
|
{{range . -}}
|
||||||
|
| {{.id | printf "%10d" }} | {{.filename | printf "%-28s"}} | {{.size | printf "%10d"}} | {{.author.name | printf "%-12s"}} | {{.created | age | printf "%-12s"}} |
|
||||||
|
{{end -}}
|
||||||
|
+{{ "-" | rep 12 }}+{{ "-" | rep 30 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||||
`
|
`
|
||||||
|
|
||||||
const defaultViewTemplate = `{{/* view template */ -}}
|
const defaultViewTemplate = `{{/* view template */ -}}
|
||||||
@@ -387,6 +400,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,99 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
yaml "gopkg.in/coryb/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttachCreateOptions struct {
|
||||||
|
jiracli.CommonOptions `yaml:",inline" json:",inline" figtree:",inline"`
|
||||||
|
Issue string `yaml:"issue,omitempty" json:"issue,omitempty"`
|
||||||
|
Attachment string `yaml:"attachment,omitempty" json:"attachment,omitempty"`
|
||||||
|
Filename string `yaml:"filename,omitempty" json:"filename,omitempty"`
|
||||||
|
SaveFile string `yaml:"savefile,omitempty" json:"savefile,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachCreateRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := AttachCreateOptions{}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Attach file to issue",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdAttachCreateUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdAttachCreate(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachCreateUsage(cmd *kingpin.CmdClause, opts *AttachCreateOptions) error {
|
||||||
|
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
|
||||||
|
cmd.Flag("saveFile", "Write attachment information as yaml to file").StringVar(&opts.SaveFile)
|
||||||
|
cmd.Flag("filename", "Filename to use for attachment").Short('f').StringVar(&opts.Filename)
|
||||||
|
cmd.Arg("ISSUE", "issue to assign").Required().StringVar(&opts.Issue)
|
||||||
|
cmd.Arg("ATTACHMENT", "File to attach to issue, if not provided read from stdin").StringVar(&opts.Attachment)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachCreate(o *oreo.Client, globals *jiracli.GlobalOptions, opts *AttachCreateOptions) error {
|
||||||
|
var contents *os.File
|
||||||
|
var err error
|
||||||
|
if opts.Attachment == "" {
|
||||||
|
if terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||||
|
return fmt.Errorf("ATTACHMENT argument required or redirect from STDIN")
|
||||||
|
}
|
||||||
|
contents = os.Stdin
|
||||||
|
if opts.Filename == "" {
|
||||||
|
return fmt.Errorf("--filename required when reading from stdin")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contents, err = os.Open(opts.Attachment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if opts.Filename == "" {
|
||||||
|
opts.Filename = opts.Attachment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachments, err := jira.IssueAttachFile(o, globals.Endpoint.Value, opts.Issue, opts.Filename, contents)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(sort.Reverse(attachments))
|
||||||
|
|
||||||
|
if opts.SaveFile != "" {
|
||||||
|
fh, err := os.Create(opts.SaveFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
out, err := yaml.Marshal((*attachments)[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fh.Write(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !globals.Quiet.Value {
|
||||||
|
fmt.Printf("OK %d %s\n", (*attachments)[0].ID, (*attachments)[0].Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Browse.Value {
|
||||||
|
return CmdBrowse(globals, opts.Issue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttachGetOptions struct {
|
||||||
|
AttachmentID string `yaml:"attachment-id,omitempty" json:"attachment-id,omitempty"`
|
||||||
|
OutputFile string `yaml:"output-file,omitempty" json:"output-file,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachGetRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := AttachGetOptions{}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Fetch attachment",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdAttachGetUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdAttachGet(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachGetUsage(cmd *kingpin.CmdClause, opts *AttachGetOptions) error {
|
||||||
|
cmd.Flag("output", "Write attachment to specified file name, '-' for stdout").Short('o').StringVar(&opts.OutputFile)
|
||||||
|
cmd.Arg("ATTACHMENT-ID", "Attachment id to fetch").StringVar(&opts.AttachmentID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachGet(o *oreo.Client, globals *jiracli.GlobalOptions, opts *AttachGetOptions) error {
|
||||||
|
attachment, err := jira.GetAttachment(o, globals.Endpoint.Value, opts.AttachmentID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := o.Get(attachment.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var output *os.File
|
||||||
|
if opts.OutputFile == "-" {
|
||||||
|
output = os.Stdout
|
||||||
|
} else if opts.OutputFile != "" {
|
||||||
|
output, err = os.Create(opts.OutputFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer output.Close()
|
||||||
|
} else {
|
||||||
|
output, err = os.Create(attachment.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer output.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(output, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
output.Close()
|
||||||
|
if opts.OutputFile != "-" && !globals.Quiet.Value {
|
||||||
|
fmt.Printf("OK Wrote %s\n", output.Name())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"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 AttachListOptions struct {
|
||||||
|
jiracli.CommonOptions `yaml:",inline" json:",inline" figtree:",inline"`
|
||||||
|
Issue string `yaml:"issue,omitempty" json:"issue,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachListRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := AttachListOptions{
|
||||||
|
CommonOptions: jiracli.CommonOptions{
|
||||||
|
Template: figtree.NewStringOption("attach-list"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Prints issue details",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdAttachListUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdAttachList(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachListUsage(cmd *kingpin.CmdClause, opts *AttachListOptions) error {
|
||||||
|
jiracli.BrowseUsage(cmd, &opts.CommonOptions)
|
||||||
|
jiracli.TemplateUsage(cmd, &opts.CommonOptions)
|
||||||
|
cmd.Arg("ISSUE", "Issue id to lookup attachments").Required().StringVar(&opts.Issue)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachList(o *oreo.Client, globals *jiracli.GlobalOptions, opts *AttachListOptions) error {
|
||||||
|
data, err := jira.GetIssue(o, globals.Endpoint.Value, opts.Issue, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to conver the interface{} "attachment" field to an actual
|
||||||
|
// ListOfAttachment object so we can sort it
|
||||||
|
var attachments jiradata.ListOfAttachment
|
||||||
|
err = jiracli.ConvertType(data.Fields["attachment"], &attachments)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sort.Sort(&attachments)
|
||||||
|
|
||||||
|
if err := opts.PrintTemplate(attachments); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if opts.Browse.Value {
|
||||||
|
return CmdBrowse(globals, opts.Issue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package jiracmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coryb/figtree"
|
||||||
|
"github.com/coryb/oreo"
|
||||||
|
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
|
||||||
|
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
|
||||||
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttachRemoveOptions struct {
|
||||||
|
AttachmentID string `yaml:"attachment-id,omitempty" json:"attachment-id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachRemoveRegistry() *jiracli.CommandRegistryEntry {
|
||||||
|
opts := AttachRemoveOptions{}
|
||||||
|
|
||||||
|
return &jiracli.CommandRegistryEntry{
|
||||||
|
"Delete attachment",
|
||||||
|
func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
|
||||||
|
jiracli.LoadConfigs(cmd, fig, &opts)
|
||||||
|
return CmdAttachRemoveUsage(cmd, &opts)
|
||||||
|
},
|
||||||
|
func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
|
||||||
|
return CmdAttachRemove(o, globals, &opts)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachRemoveUsage(cmd *kingpin.CmdClause, opts *AttachRemoveOptions) error {
|
||||||
|
cmd.Arg("ATTACHMENT-ID", "Attachment id to fetch").StringVar(&opts.AttachmentID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CmdAttachRemove(o *oreo.Client, globals *jiracli.GlobalOptions, opts *AttachRemoveOptions) error {
|
||||||
|
if err := jira.RemoveAttachment(o, globals.Endpoint.Value, opts.AttachmentID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !globals.Quiet.Value {
|
||||||
|
fmt.Printf("OK Deleted Attachment %s\n", opts.AttachmentID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -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,issuetype"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
+1
-1
@@ -31,7 +31,7 @@ func CmdListRegistry() *jiracli.CommandRegistryEntry {
|
|||||||
opts.MaxResults = 500
|
opts.MaxResults = 500
|
||||||
}
|
}
|
||||||
if opts.QueryFields == "" {
|
if opts.QueryFields == "" {
|
||||||
opts.QueryFields = "assignee,created,priority,reporter,status,summary,updated"
|
opts.QueryFields = "assignee,created,priority,reporter,status,summary,updated,issuetype"
|
||||||
}
|
}
|
||||||
if opts.Sort == "" {
|
if opts.Sort == "" {
|
||||||
opts.Sort = "priority asc, key"
|
opts.Sort = "priority asc, key"
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Code is Generated by SlipScheme Project:
|
||||||
|
// https://github.com/coryb/slipscheme
|
||||||
|
//
|
||||||
|
// Generated with command:
|
||||||
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// DO NOT EDIT //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Attachment defined from schema:
|
||||||
|
// {
|
||||||
|
// "title": "Attachment",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "author": {
|
||||||
|
// "title": "User",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "accountId": {
|
||||||
|
// "title": "accountId",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "active": {
|
||||||
|
// "title": "active",
|
||||||
|
// "type": "boolean"
|
||||||
|
// },
|
||||||
|
// "applicationRoles": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "avatarUrls": {
|
||||||
|
// "title": "avatarUrls",
|
||||||
|
// "type": "object",
|
||||||
|
// "patternProperties": {
|
||||||
|
// ".+": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "displayName": {
|
||||||
|
// "title": "displayName",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "emailAddress": {
|
||||||
|
// "title": "emailAddress",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "expand": {
|
||||||
|
// "title": "expand",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "groups": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "key": {
|
||||||
|
// "title": "key",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "locale": {
|
||||||
|
// "title": "locale",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "name": {
|
||||||
|
// "title": "name",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "title": "self",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "timeZone": {
|
||||||
|
// "title": "timeZone",
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "content": {
|
||||||
|
// "title": "content",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "created": {
|
||||||
|
// "title": "created",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "filename": {
|
||||||
|
// "title": "filename",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "id": {
|
||||||
|
// "title": "id",
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "mimeType": {
|
||||||
|
// "title": "mimeType",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "properties": {
|
||||||
|
// "title": "properties",
|
||||||
|
// "type": "object",
|
||||||
|
// "patternProperties": {
|
||||||
|
// ".+": {}
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "title": "self",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "title": "size",
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "thumbnail": {
|
||||||
|
// "title": "thumbnail",
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
type Attachment struct {
|
||||||
|
Author *User `json:"author,omitempty" yaml:"author,omitempty"`
|
||||||
|
Content string `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
|
Created string `json:"created,omitempty" yaml:"created,omitempty"`
|
||||||
|
Filename string `json:"filename,omitempty" yaml:"filename,omitempty"`
|
||||||
|
ID IntOrString `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
|
MimeType string `json:"mimeType,omitempty" yaml:"mimeType,omitempty"`
|
||||||
|
Properties map[string]interface{} `json:"properties,omitempty" yaml:"properties,omitempty"`
|
||||||
|
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
||||||
|
Size int `json:"size,omitempty" yaml:"size,omitempty"`
|
||||||
|
Thumbnail string `json:"thumbnail,omitempty" yaml:"thumbnail,omitempty"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
type EpicIssues struct {
|
||||||
|
Issues []string `json:"issues,omitempty" yaml:"issues,omitempty"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Code is Generated by SlipScheme Project:
|
||||||
|
// https://github.com/coryb/slipscheme
|
||||||
|
//
|
||||||
|
// Generated with command:
|
||||||
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// DO NOT EDIT //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Group defined from schema:
|
||||||
|
// {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
type Group struct {
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Code is Generated by SlipScheme Project:
|
||||||
|
// https://github.com/coryb/slipscheme
|
||||||
|
//
|
||||||
|
// Generated with command:
|
||||||
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// DO NOT EDIT //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Groups defined from schema:
|
||||||
|
// {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
type Groups []*Group
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Code is Generated by SlipScheme Project:
|
||||||
|
// https://github.com/coryb/slipscheme
|
||||||
|
//
|
||||||
|
// Generated with command:
|
||||||
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// DO NOT EDIT //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ListOfAttachment defined from schema:
|
||||||
|
// {
|
||||||
|
// "title": "List of Attachment",
|
||||||
|
// "id": "https://docs.atlassian.com/jira/REST/schema/list-of-attachment#",
|
||||||
|
// "type": "array",
|
||||||
|
// "definitions": {
|
||||||
|
// "simple-list-wrapper": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "items": {
|
||||||
|
// "title": "Attachment",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "author": {
|
||||||
|
// "title": "User",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "accountId": {
|
||||||
|
// "title": "accountId",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "active": {
|
||||||
|
// "title": "active",
|
||||||
|
// "type": "boolean"
|
||||||
|
// },
|
||||||
|
// "applicationRoles": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "avatarUrls": {
|
||||||
|
// "title": "avatarUrls",
|
||||||
|
// "type": "object",
|
||||||
|
// "patternProperties": {
|
||||||
|
// ".+": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "displayName": {
|
||||||
|
// "title": "displayName",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "emailAddress": {
|
||||||
|
// "title": "emailAddress",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "expand": {
|
||||||
|
// "title": "expand",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "groups": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "key": {
|
||||||
|
// "title": "key",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "locale": {
|
||||||
|
// "title": "locale",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "name": {
|
||||||
|
// "title": "name",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "title": "self",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "timeZone": {
|
||||||
|
// "title": "timeZone",
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "content": {
|
||||||
|
// "title": "content",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "created": {
|
||||||
|
// "title": "created",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "filename": {
|
||||||
|
// "title": "filename",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "id": {
|
||||||
|
// "title": "id",
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "mimeType": {
|
||||||
|
// "title": "mimeType",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "properties": {
|
||||||
|
// "title": "properties",
|
||||||
|
// "type": "object",
|
||||||
|
// "patternProperties": {
|
||||||
|
// ".+": {}
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "title": "self",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "title": "size",
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "thumbnail": {
|
||||||
|
// "title": "thumbnail",
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
type ListOfAttachment []*Attachment
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
func (l *ListOfAttachment) Len() int {
|
||||||
|
return len(*l)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListOfAttachment) Less(i, j int) bool {
|
||||||
|
return (*l)[i].ID < (*l)[j].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListOfAttachment) Swap(i, j int) {
|
||||||
|
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Code is Generated by SlipScheme Project:
|
||||||
|
// https://github.com/coryb/slipscheme
|
||||||
|
//
|
||||||
|
// Generated with command:
|
||||||
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// DO NOT EDIT //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// SimpleListWrapper defined from schema:
|
||||||
|
// {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
type SimpleListWrapper struct {
|
||||||
|
Items Groups `json:"items,omitempty" yaml:"items,omitempty"`
|
||||||
|
MaxResults int `json:"max-results,omitempty" yaml:"max-results,omitempty"`
|
||||||
|
Size int `json:"size,omitempty" yaml:"size,omitempty"`
|
||||||
|
}
|
||||||
+85
-10
@@ -5,7 +5,7 @@ package jiradata
|
|||||||
// https://github.com/coryb/slipscheme
|
// https://github.com/coryb/slipscheme
|
||||||
//
|
//
|
||||||
// Generated with command:
|
// Generated with command:
|
||||||
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/WorklogWithPagination.json
|
// slipscheme -dir jiradata -pkg jiradata -overwrite schemas/ListofAttachment.json
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
// DO NOT EDIT //
|
// DO NOT EDIT //
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
@@ -16,12 +16,42 @@ package jiradata
|
|||||||
// "type": "object",
|
// "type": "object",
|
||||||
// "properties": {
|
// "properties": {
|
||||||
// "accountId": {
|
// "accountId": {
|
||||||
|
// "title": "accountId",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
// "active": {
|
// "active": {
|
||||||
|
// "title": "active",
|
||||||
// "type": "boolean"
|
// "type": "boolean"
|
||||||
// },
|
// },
|
||||||
|
// "applicationRoles": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
// "avatarUrls": {
|
// "avatarUrls": {
|
||||||
|
// "title": "avatarUrls",
|
||||||
// "type": "object",
|
// "type": "object",
|
||||||
// "patternProperties": {
|
// "patternProperties": {
|
||||||
// ".+": {
|
// ".+": {
|
||||||
@@ -30,33 +60,78 @@ package jiradata
|
|||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// "displayName": {
|
// "displayName": {
|
||||||
|
// "title": "displayName",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
// "emailAddress": {
|
// "emailAddress": {
|
||||||
|
// "title": "emailAddress",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
|
// "expand": {
|
||||||
|
// "title": "expand",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "groups": {
|
||||||
|
// "title": "Simple List Wrapper",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "items": {
|
||||||
|
// "type": "array",
|
||||||
|
// "items": {
|
||||||
|
// "title": "Group",
|
||||||
|
// "type": "object",
|
||||||
|
// "properties": {
|
||||||
|
// "name": {
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "self": {
|
||||||
|
// "type": "string"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "max-results": {
|
||||||
|
// "type": "integer"
|
||||||
|
// },
|
||||||
|
// "size": {
|
||||||
|
// "type": "integer"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
// "key": {
|
// "key": {
|
||||||
|
// "title": "key",
|
||||||
|
// "type": "string"
|
||||||
|
// },
|
||||||
|
// "locale": {
|
||||||
|
// "title": "locale",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
// "name": {
|
// "name": {
|
||||||
|
// "title": "name",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
// "self": {
|
// "self": {
|
||||||
|
// "title": "self",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// },
|
// },
|
||||||
// "timeZone": {
|
// "timeZone": {
|
||||||
|
// "title": "timeZone",
|
||||||
// "type": "string"
|
// "type": "string"
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
type User struct {
|
type User struct {
|
||||||
AccountID string `json:"accountId,omitempty" yaml:"accountId,omitempty"`
|
AccountID string `json:"accountId,omitempty" yaml:"accountId,omitempty"`
|
||||||
Active bool `json:"active,omitempty" yaml:"active,omitempty"`
|
Active bool `json:"active,omitempty" yaml:"active,omitempty"`
|
||||||
AvatarUrls map[string]string `json:"avatarUrls,omitempty" yaml:"avatarUrls,omitempty"`
|
ApplicationRoles *SimpleListWrapper `json:"applicationRoles,omitempty" yaml:"applicationRoles,omitempty"`
|
||||||
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty"`
|
AvatarUrls map[string]string `json:"avatarUrls,omitempty" yaml:"avatarUrls,omitempty"`
|
||||||
EmailAddress string `json:"emailAddress,omitempty" yaml:"emailAddress,omitempty"`
|
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty"`
|
||||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
EmailAddress string `json:"emailAddress,omitempty" yaml:"emailAddress,omitempty"`
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Expand string `json:"expand,omitempty" yaml:"expand,omitempty"`
|
||||||
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
Groups *SimpleListWrapper `json:"groups,omitempty" yaml:"groups,omitempty"`
|
||||||
TimeZone string `json:"timeZone,omitempty" yaml:"timeZone,omitempty"`
|
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||||
|
Locale string `json:"locale,omitempty" yaml:"locale,omitempty"`
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
||||||
|
TimeZone string `json:"timeZone,omitempty" yaml:"timeZone,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package jiradata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this is for some bad schemas like Attachments.ID where in some api's it is an `int` and some it is a `string`
|
||||||
|
type IntOrString int
|
||||||
|
|
||||||
|
func (i *IntOrString) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var tmp string
|
||||||
|
if err := unmarshal(&tmp); err != nil {
|
||||||
|
return unmarshal((*int)(i))
|
||||||
|
}
|
||||||
|
tmpInt, err := strconv.Atoi(tmp)
|
||||||
|
*i = IntOrString(tmpInt)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IntOrString) UnmarshalJSON(b []byte) error {
|
||||||
|
var tmp string
|
||||||
|
if err := json.Unmarshal(b, &tmp); err != nil {
|
||||||
|
return json.Unmarshal(b, (*int)(i))
|
||||||
|
}
|
||||||
|
tmpInt, err := strconv.Atoi(tmp)
|
||||||
|
*i = IntOrString(tmpInt)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
+5
-5
@@ -58,11 +58,11 @@ EOF
|
|||||||
|
|
||||||
RUNS $jira ls --project BASIC --template table
|
RUNS $jira ls --project BASIC --template table
|
||||||
DIFF <<EOF
|
DIFF <<EOF
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
| Issue | Summary | Type | Priority | Status | Age | Reporter | Assignee |
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
| $(printf %-14s $issue) | summary | Medium | To Do | a minute | gojira | gojira |
|
| $(printf %-14s $issue) | summary | Bug | Medium | To Do | a minute | gojira | gojira |
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|||||||
+6
-14
@@ -46,15 +46,7 @@ EOF
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
RUNS $jira env
|
RUNS $jira env
|
||||||
DIFF <<'EOF'
|
GREP ^JIRA_PROJECT=BASIC
|
||||||
JIRACLOUD=1
|
|
||||||
JIRA_CUSTOM_COMMANDS=[{"name":"env","script":"env | sort | grep JIRA","help":"print the JIRA environment variables available to custom commands"},{"name":"print-project","script":"echo $JIRA_PROJECT","help":"print the name of the configured project"},{"name":"jira-path","script":"echo {{jira}}","help":"print the path the jira command that is running this alias"},{"name":"mine","script":"if [ -n \"$JIRA_PROJECT\" ]; then\n # if `project: ...` configured just list the issues for current project\n {{jira}} list --template table --query \"resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created\"\nelse\n # otherwise list issues for all project\n {{jira}} list --template table --query \"resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created\"\nfi","help":"display issues assigned to me"},{"name":"argtest","args":[{"name":"ARG","help":"string to echo for testing"}],"script":"echo {{args.ARG}}","help":"testing passing args"},{"name":"opttest","options":[{"name":"OPT","help":"string to echo for testing"}],"script":"echo {{options.OPT}}","help":"testing passing option flags"}]
|
|
||||||
JIRA_ENDPOINT=https://go-jira.atlassian.net
|
|
||||||
JIRA_LOG_FORMAT=%{level:-5s} %{message}
|
|
||||||
JIRA_PASSWORD_SOURCE=pass
|
|
||||||
JIRA_PROJECT=BASIC
|
|
||||||
JIRA_USER=gojira
|
|
||||||
EOF
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
## Testing the example custom commands, argtest
|
## Testing the example custom commands, argtest
|
||||||
@@ -80,9 +72,9 @@ EOF
|
|||||||
|
|
||||||
RUNS $jira mine
|
RUNS $jira mine
|
||||||
DIFF <<EOF
|
DIFF <<EOF
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
| Issue | Summary | Type | Priority | Status | Age | Reporter | Assignee |
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
| $(printf %-14s $issue) | summary | Medium | To Do | a minute | gojira | gojira |
|
| $(printf %-14s $issue) | summary | Bug | Medium | To Do | a minute | gojira | gojira |
|
||||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
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 | Type | 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 | Type | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| $(printf %-14s $issue1) | summary | Bug | Medium | To Do | a minute | gojira | gojira |
|
||||||
|
| $(printf %-14s $issue2) | summary | Bug | 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 | Type | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
| $(printf %-14s $issue2) | summary | Bug | 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 | Type | Priority | Status | Age | Reporter | Assignee |
|
||||||
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
+----------------+------------------------------------------+--------------+--------------+--------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
Executable
+189
@@ -0,0 +1,189 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
|
||||||
|
cd $(dirname $0)
|
||||||
|
jira="../jira"
|
||||||
|
. env.sh
|
||||||
|
|
||||||
|
PLAN 43
|
||||||
|
|
||||||
|
# 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 issue
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira create --project BASIC -o summary="Attach To Me" -o description=description --noedit --saveFile issue.props
|
||||||
|
issue=$(awk '/issue/{print $2}' issue.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $issue $ENDPOINT/browse/$issue
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Attach via stdin
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach create $issue --filename README.md --saveFile attach.props < ./README.md
|
||||||
|
attach1=$(awk '/^id:/{print $2}' attach.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $attach1 $ENDPOINT/secure/attachment/$attach1/README.md
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Attach binary file
|
||||||
|
###############################################################################
|
||||||
|
RUNS dd of=garbage.bin if=/dev/urandom count=1k bs=1k
|
||||||
|
RUNS $jira attach create $issue garbage.bin --saveFile attach.props
|
||||||
|
attach2=$(awk '/^id:/{print $2}' attach.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $attach2 $ENDPOINT/secure/attachment/$attach2/garbage.bin
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Attach binary file with different name
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach create $issue garbage.bin --filename foobar.bin --saveFile attach.props
|
||||||
|
attach3=$(awk '/^id:/{print $2}' attach.props)
|
||||||
|
|
||||||
|
DIFF <<EOF
|
||||||
|
OK $attach3 $ENDPOINT/secure/attachment/$attach3/foobar.bin
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## List attachments
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach list $issue
|
||||||
|
DIFF <<EOF
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| id | filename | bytes | user | created |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| $(printf %10s $attach1) | README.md | 1238 | gojira | a minute |
|
||||||
|
| $(printf %10s $attach2) | garbage.bin | 1048576 | gojira | a minute |
|
||||||
|
| $(printf %10s $attach3) | foobar.bin | 1048576 | gojira | a minute |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch text attachment
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach get $attach1 -o attach1.txt
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Wrote attach1.txt
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q README.md attach1.txt
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch text attachment to stdout
|
||||||
|
###############################################################################
|
||||||
|
RUNS sh -c "$jira attach get $attach1 -o- > attach1.txt"
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q README.md attach1.txt
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch text attachment as same name
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach get $attach1
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Wrote README.md
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS git diff README.md
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch binary attachment
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach get $attach2 --output binary.out
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Wrote binary.out
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q garbage.bin binary.out
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch binary attachment to stdout
|
||||||
|
###############################################################################
|
||||||
|
RUNS sh -c "$jira attach get $attach2 -o- > binary.out"
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q garbage.bin binary.out
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch binary attachment
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach get $attach3
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Wrote foobar.bin
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q garbage.bin foobar.bin
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Fetch binary attachment to stdout
|
||||||
|
###############################################################################
|
||||||
|
RUNS sh -c "$jira attach get $attach3 --output=- > binary.out"
|
||||||
|
|
||||||
|
# verify no diffs
|
||||||
|
RUNS diff -q garbage.bin binary.out
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Delete attachment
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach remove $attach1
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Deleted Attachment $attach1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUNS $jira attach list $issue
|
||||||
|
DIFF <<EOF
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| id | filename | bytes | user | created |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| $(printf %10s $attach2) | garbage.bin | 1048576 | gojira | a minute |
|
||||||
|
| $(printf %10s $attach3) | foobar.bin | 1048576 | gojira | a minute |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Delete attachment
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach rm $attach2
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Deleted Attachment $attach2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUNS $jira attach list $issue
|
||||||
|
DIFF <<EOF
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| id | filename | bytes | user | created |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| $(printf %10s $attach3) | foobar.bin | 1048576 | gojira | a minute |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## Delete last
|
||||||
|
###############################################################################
|
||||||
|
RUNS $jira attach rm $attach3
|
||||||
|
DIFF <<EOF
|
||||||
|
OK Deleted Attachment $attach3
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUNS $jira attach list $issue
|
||||||
|
DIFF <<EOF
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
| id | filename | bytes | user | created |
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
+------------+------------------------------+------------+--------------+--------------+
|
||||||
|
EOF
|
||||||
Reference in New Issue
Block a user