mirror of
https://github.com/Threnklyn/jira.git
synced 2026-05-19 20:53:27 +02:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba08d51437 | |||
| 09d718b5d8 | |||
| e3e84d7aa0 | |||
| a4f1d754e4 | |||
| 683541de1e | |||
| e0fd6bab66 | |||
| 5ca096ab6e | |||
| ac515e2743 | |||
| be4a5f9156 | |||
| 7f10eaa667 | |||
| b326623ed2 | |||
| 72c78c6c1c | |||
| 5df5a39405 | |||
| bd54ecc4f6 | |||
| 073e0bdcce | |||
| 1347ebe6b6 | |||
| c7565b08a1 | |||
| 01067e859c | |||
| 8b174625d9 | |||
| 8acc177627 | |||
| 8d9db0e399 | |||
| 998e4601c0 | |||
| 2df70edd00 | |||
| f73b3a5dc8 | |||
| e74c94b030 | |||
| c18d2140e4 | |||
| 2b56833c1c | |||
| fe69ad1cec | |||
| 3b18a1863c | |||
| d6d6578b11 | |||
| 2b433dda40 | |||
| 08a24e7dc3 | |||
| a746ddc6fb | |||
| e254435734 | |||
| 14298bfa52 | |||
| a3633aa537 | |||
| 2a8b6521dc | |||
| 4cc172de6b | |||
| 0dd6061992 | |||
| 9d12f56332 | |||
| 824dd2f725 | |||
| 657bc59c8f | |||
| ec1914dfde | |||
| a22911a3f9 | |||
| 1f6191425f | |||
| f896555299 | |||
| e0b2c2d240 | |||
| a5cb93f112 | |||
| cbbf335439 | |||
| 92b5e38912 | |||
| 6260e4964f | |||
| 485d65f12b |
+4
-1
@@ -9,4 +9,7 @@ jira
|
||||
jira.exe
|
||||
schemas/*.json
|
||||
t/issue.props
|
||||
t/.jira.d/templates
|
||||
t/.jira.d/templates
|
||||
dist/
|
||||
src/
|
||||
t/.maven-cache
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
sudo: true
|
||||
before_install:
|
||||
- sudo apt-get update && sudo apt-get install -y libgnome-keyring-dev
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
script:
|
||||
- make vet
|
||||
- make lint
|
||||
- make
|
||||
- JIRACLOUD=1 ./t/100basic.t -w -a 2>&1
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- t/.maven-cache
|
||||
@@ -1,5 +1,37 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.9 - 2016-12-18
|
||||
|
||||
* only warn about needing login when not already running the login command [Cory Bennett] [[6c24e55](https://github.com/Netflix-Skunkworks/go-jira/commit/6c24e55)]
|
||||
* fix(http): Add proxy transport [William Hearn] [[4bd740b](https://github.com/Netflix-Skunkworks/go-jira/commit/4bd740b)]
|
||||
* fix(http): Add proxy transport [William Hearn] [[2dff6c9](https://github.com/Netflix-Skunkworks/go-jira/commit/2dff6c9)]
|
||||
|
||||
## 0.1.8 - 2016-11-24
|
||||
|
||||
* [[#12](https://github.com/Netflix-Skunkworks/go-jira/issues/12)] integrate with keyring for password storage and provide http basic auth credentials for every request since most jira services have websudo enabled with does not allow cookie based authentication [Cory Bennett] [[b8a6e57](https://github.com/Netflix-Skunkworks/go-jira/commit/b8a6e57)]
|
||||
* Cleaning up usage [Jay Shirley] [[8add52b](https://github.com/Netflix-Skunkworks/go-jira/commit/8add52b)]
|
||||
* Update usage [Jay Shirley] [[b56e32a](https://github.com/Netflix-Skunkworks/go-jira/commit/b56e32a)]
|
||||
* use gopkg.in for links to maintain version compatibility [Cory Bennett] [[1414d1f](https://github.com/Netflix-Skunkworks/go-jira/commit/1414d1f)]
|
||||
* golint [Cory Bennett] [[44cdebf](https://github.com/Netflix-Skunkworks/go-jira/commit/44cdebf)]
|
||||
* add "rank" command allow ordering backlog issues in agile projects [Cory Bennett] [[e4cc9c6](https://github.com/Netflix-Skunkworks/go-jira/commit/e4cc9c6)]
|
||||
* Adding a unixproxy mechanism [Jay Shirley] [[5b9c0dd](https://github.com/Netflix-Skunkworks/go-jira/commit/5b9c0dd)]
|
||||
|
||||
## 0.1.7 - 2016-08-24
|
||||
|
||||
* Prefer transition names which match exactly [Don Brower] [[e40f9c1](https://github.com/Netflix-Skunkworks/go-jira/commit/e40f9c1)]
|
||||
* update tempates to make them more readable with space trimming added to go-1.6 [Cory Bennett] [[693b3e4](https://github.com/Netflix-Skunkworks/go-jira/commit/693b3e4)]
|
||||
|
||||
## 0.1.6 - 2016-08-21
|
||||
|
||||
* make "worklogs" command print output through template allow "add worklog" command to open edit template [Cory Bennett] [[cc3fbee](https://github.com/Netflix-Skunkworks/go-jira/commit/cc3fbee)]
|
||||
* remove extra newline at end of worklogs template [Cory Bennett] [[d08ef15](https://github.com/Netflix-Skunkworks/go-jira/commit/d08ef15)]
|
||||
* adding worklog related templates [Cory Bennett] [[ab1cd27](https://github.com/Netflix-Skunkworks/go-jira/commit/ab1cd27)]
|
||||
|
||||
## 0.1.5 - 2016-08-21
|
||||
|
||||
* update for golint [Cory Bennett] [[5a4e17c](https://github.com/Netflix-Skunkworks/go-jira/commit/5a4e17c)]
|
||||
* fix for go vet [Cory Bennett] [[355fb42](https://github.com/Netflix-Skunkworks/go-jira/commit/355fb42)]
|
||||
|
||||
## 0.1.4 - 2016-08-12
|
||||
|
||||
* when running "dups" on a Process Management Project type, you have to start/stop the task to resolve it [Cory Bennett] [[2c91905](https://github.com/Netflix-Skunkworks/go-jira/commit/2c91905)]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
PLATFORMS= \
|
||||
freebsd-amd64 \
|
||||
linux-386 \
|
||||
linux-amd64 \
|
||||
windows-386 \
|
||||
windows-amd64 \
|
||||
darwin-amd64 \
|
||||
freebsd/amd64 \
|
||||
linux/386 \
|
||||
linux/amd64 \
|
||||
windows/386 \
|
||||
windows/amd64 \
|
||||
darwin/amd64 \
|
||||
$(NULL)
|
||||
|
||||
# freebsd-386 \
|
||||
@@ -45,7 +45,7 @@ else
|
||||
GOBUILD=go build -v -ldflags "$(LDFLAGS) -s"
|
||||
endif
|
||||
|
||||
build: src/github.com/Netflix-Skunkworks/go-jira
|
||||
build: src/gopkg.in/Netflix-Skunkworks/go-jira.v0
|
||||
$(GOBUILD) -o '$(BIN)' main/main.go
|
||||
|
||||
debug:
|
||||
@@ -53,23 +53,41 @@ debug:
|
||||
|
||||
src/%:
|
||||
mkdir -p $(@D)
|
||||
test -L $@ || ln -sf '$(GOPATH)' $@
|
||||
test -L $@ || ln -sf '../../..' $@
|
||||
go get -v $* $*/main
|
||||
|
||||
vet:
|
||||
@go vet .
|
||||
@go vet ./data
|
||||
@go vet ./main
|
||||
|
||||
lint:
|
||||
@go get github.com/golang/lint/golint
|
||||
@./bin/golint .
|
||||
@./bin/golint ./data
|
||||
@./bin/golint ./main
|
||||
|
||||
cross-setup:
|
||||
for p in $(PLATFORMS); do \
|
||||
echo Building for $$p"; \
|
||||
cd $(GOROOT)/src && sudo GOROOT_BOOTSTRAP=$(GOROOT) GOOS=$${p/-*/} GOARCH=$${p/*-/} bash ./make.bash --no-clean; \
|
||||
done
|
||||
|
||||
all:
|
||||
rm -rf $(DIST); \
|
||||
mkdir -p $(DIST); \
|
||||
for p in $(PLATFORMS); do \
|
||||
echo "Building for $$p"; \
|
||||
${MAKE} build GOOS=$${p/-*/} GOARCH=$${p/*-/} BIN=$(DIST)/$(NAME)-$$p; \
|
||||
done
|
||||
for x in $(DIST)/jira-windows-*; do mv $$x $$x.exe; done
|
||||
all: src/gopkg.in/Netflix-Skunkworks/go-jira.v0
|
||||
docker pull karalabe/xgo-latest
|
||||
rm -rf dist
|
||||
mkdir -p dist
|
||||
docker run --rm -e EXT_GOPATH=/gopath -v $$(pwd):/gopath -e TARGETS="$(PLATFORMS)" -v $$(pwd)/dist:/build karalabe/xgo-latest gopkg.in/Netflix-Skunkworks/go-jira.v0/main
|
||||
cd $(DIST) && for x in main-*; do mv $$x jira-$$(echo $$x | cut -c 6-); done
|
||||
|
||||
# all:
|
||||
# rm -rf $(DIST); \
|
||||
# mkdir -p $(DIST); \
|
||||
# for p in $(PLATFORMS); do \
|
||||
# echo "Building for $$p"; \
|
||||
# ${MAKE} build GOOS=$${p/-*/} GOARCH=$${p/*-/} BIN=$(DIST)/$(NAME)-$$p; \
|
||||
# done
|
||||
# for x in $(DIST)/jira-windows-*; do mv $$x $$x.exe; done
|
||||
|
||||
fmt:
|
||||
gofmt -s -w main/*.go *.go
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
[](https://gitter.im/go-jira-cli/help?utm_source=badge&utm_medium=badge&utm_content=badge)
|
||||
[](https://travis-ci.org/Netflix-Skunkworks/go-jira)
|
||||
[](https://godoc.org/gopkg.in/Netflix-Skunkworks/go-jira.v0)
|
||||
|
||||
|
||||
# go-jira
|
||||
simple command line client for Atlassian's Jira service written in Go
|
||||
@@ -35,7 +38,7 @@ jira trans close GOJIRA-321 -o resolution="Won't Fix" --noedit
|
||||
# same as above
|
||||
jira close GOJIRA-321 -o resolution="Won't Fix"
|
||||
|
||||
jira repopen GOJIRA-321 -m "reopening" # reopen issue
|
||||
jira reopen GOJIRA-321 -m "reopening" # reopen issue
|
||||
|
||||
jira watch GOJIRA-321 # add self as watcher to the issue
|
||||
|
||||
|
||||
@@ -5,9 +5,6 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/kballard/go-shellquote"
|
||||
"gopkg.in/coryb/yaml.v2"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
@@ -20,13 +17,20 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kballard/go-shellquote"
|
||||
"github.com/tmc/keyring"
|
||||
"gopkg.in/coryb/yaml.v2"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
log = logging.MustGetLogger("jira")
|
||||
log = logging.MustGetLogger("jira")
|
||||
// VERSION is the go-jira library version
|
||||
VERSION string
|
||||
)
|
||||
|
||||
// Cli is go-jira client object
|
||||
type Cli struct {
|
||||
endpoint *url.URL
|
||||
opts map[string]interface{}
|
||||
@@ -34,32 +38,43 @@ type Cli struct {
|
||||
ua *http.Client
|
||||
}
|
||||
|
||||
// New creates go-jira client object
|
||||
func New(opts map[string]interface{}) *Cli {
|
||||
homedir := homedir()
|
||||
cookieJar, _ := cookiejar.New(nil)
|
||||
endpoint, _ := opts["endpoint"].(string)
|
||||
url, _ := url.Parse(strings.TrimRight(endpoint, "/"))
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{},
|
||||
}
|
||||
|
||||
if project, ok := opts["project"].(string); ok {
|
||||
opts["project"] = strings.ToUpper(project)
|
||||
}
|
||||
|
||||
if insecureSkipVerify, ok := opts["insecure"].(bool); ok {
|
||||
transport.TLSClientConfig.InsecureSkipVerify = insecureSkipVerify
|
||||
var ua *http.Client
|
||||
if unixProxyPath, ok := opts["unixproxy"].(string); ok {
|
||||
ua = &http.Client{
|
||||
Jar: cookieJar,
|
||||
Transport: UnixProxy(unixProxyPath),
|
||||
}
|
||||
} else {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{},
|
||||
}
|
||||
if insecureSkipVerify, ok := opts["insecure"].(bool); ok {
|
||||
transport.TLSClientConfig.InsecureSkipVerify = insecureSkipVerify
|
||||
}
|
||||
|
||||
ua = &http.Client{
|
||||
Jar: cookieJar,
|
||||
Transport: transport,
|
||||
}
|
||||
}
|
||||
|
||||
cli := &Cli{
|
||||
endpoint: url,
|
||||
opts: opts,
|
||||
cookieFile: filepath.Join(homedir, ".jira.d", "cookies.js"),
|
||||
ua: &http.Client{
|
||||
Jar: cookieJar,
|
||||
Transport: transport,
|
||||
},
|
||||
ua: ua,
|
||||
}
|
||||
|
||||
cli.ua.Jar.SetCookies(url, cli.loadCookies())
|
||||
@@ -120,7 +135,7 @@ func (c *Cli) loadCookies() []*http.Cookie {
|
||||
log.Errorf("Failed to open %s: %s", c.cookieFile, err)
|
||||
panic(err)
|
||||
}
|
||||
cookies := make([]*http.Cookie, 0)
|
||||
cookies := []*http.Cookie{}
|
||||
err = json.Unmarshal(bytes, &cookies)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to parse json from file %s: %s", c.cookieFile, err)
|
||||
@@ -140,44 +155,42 @@ func (c *Cli) put(uri string, content string) (*http.Response, error) {
|
||||
return c.makeRequestWithContent("PUT", uri, content)
|
||||
}
|
||||
|
||||
func (c *Cli) delete(uri string) (*http.Response, error) {
|
||||
func (c *Cli) delete(uri string) (resp *http.Response, err error) {
|
||||
method := "DELETE"
|
||||
req, _ := http.NewRequest(method, uri, nil)
|
||||
log.Infof("%s %s", req.Method, req.URL.String())
|
||||
if resp, err := c.makeRequest(req); err != nil {
|
||||
if resp, err = c.makeRequest(req); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if resp.StatusCode == 401 {
|
||||
if err := c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, _ = http.NewRequest(method, uri, nil)
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
if resp.StatusCode == 401 {
|
||||
if err = c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, _ = http.NewRequest(method, uri, nil)
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *Cli) makeRequestWithContent(method string, uri string, content string) (*http.Response, error) {
|
||||
func (c *Cli) makeRequestWithContent(method string, uri string, content string) (resp *http.Response, err error) {
|
||||
buffer := bytes.NewBufferString(content)
|
||||
req, _ := http.NewRequest(method, uri, buffer)
|
||||
|
||||
log.Infof("%s %s", req.Method, req.URL.String())
|
||||
if resp, err := c.makeRequest(req); err != nil {
|
||||
if resp, err = c.makeRequest(req); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if resp.StatusCode == 401 {
|
||||
if err := c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, _ = http.NewRequest(method, uri, bytes.NewBufferString(content))
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
if resp.StatusCode == 401 {
|
||||
if err = c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, _ = http.NewRequest(method, uri, bytes.NewBufferString(content))
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *Cli) get(uri string) (*http.Response, error) {
|
||||
func (c *Cli) get(uri string) (resp *http.Response, err error) {
|
||||
req, _ := http.NewRequest("GET", uri, nil)
|
||||
log.Infof("%s %s", req.Method, req.URL.String())
|
||||
if log.IsEnabledFor(logging.DEBUG) {
|
||||
@@ -186,23 +199,32 @@ func (c *Cli) get(uri string) (*http.Response, error) {
|
||||
log.Debugf("%s", logBuffer)
|
||||
}
|
||||
|
||||
if resp, err := c.makeRequest(req); err != nil {
|
||||
if resp, err = c.makeRequest(req); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if resp.StatusCode == 401 {
|
||||
if err := c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
if resp.StatusCode == 401 {
|
||||
if err := c.CmdLogin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.makeRequest(req)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *Cli) makeRequest(req *http.Request) (resp *http.Response, err error) {
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
if val, ok := c.opts["password-keyring"].(bool); ok && val && !strings.HasSuffix(req.URL.Path, "/rest/auth/1/session") {
|
||||
user, _ := c.opts["user"].(string)
|
||||
password, _ := keyring.Get("go-jira", user)
|
||||
if password == "" {
|
||||
log.Warning("No password for user %s in keyring, please run the 'login' command first", user)
|
||||
} else {
|
||||
req.SetBasicAuth(user, password)
|
||||
}
|
||||
}
|
||||
|
||||
// this is actually done in http.send but doing it
|
||||
// here so we can log it in DumpRequest for debugging
|
||||
for _, cookie := range c.ua.Jar.Cookies(req.URL) {
|
||||
@@ -217,18 +239,17 @@ func (c *Cli) makeRequest(req *http.Request) (resp *http.Response, err error) {
|
||||
if resp, err = c.ua.Do(req); err != nil {
|
||||
log.Errorf("Failed to %s %s: %s", req.Method, req.URL.String(), err)
|
||||
return nil, err
|
||||
} else {
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 && resp.StatusCode != 401 {
|
||||
log.Errorf("response status: %s", resp.Status)
|
||||
}
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 && resp.StatusCode != 401 {
|
||||
log.Errorf("response status: %s", resp.Status)
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(resp, func(r *http.Response) {
|
||||
r.Body.Close()
|
||||
})
|
||||
runtime.SetFinalizer(resp, func(r *http.Response) {
|
||||
r.Body.Close()
|
||||
})
|
||||
|
||||
if _, ok := resp.Header["Set-Cookie"]; ok {
|
||||
c.saveCookies(resp)
|
||||
}
|
||||
if _, ok := resp.Header["Set-Cookie"]; ok {
|
||||
c.saveCookies(resp)
|
||||
}
|
||||
if log.IsEnabledFor(logging.DEBUG) {
|
||||
out, _ := httputil.DumpResponse(resp, true)
|
||||
@@ -237,6 +258,7 @@ func (c *Cli) makeRequest(req *http.Request) (resp *http.Response, err error) {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetTemplate will return the text/template for the given command name
|
||||
func (c *Cli) GetTemplate(name string) string {
|
||||
return c.getTemplate(name)
|
||||
}
|
||||
@@ -256,10 +278,9 @@ func (c *Cli) getTemplate(name string) string {
|
||||
if override, ok := c.opts["template"].(string); ok {
|
||||
if _, err := os.Stat(override); err == nil {
|
||||
return readFile(override)
|
||||
} else {
|
||||
if t := getLookedUpTemplate(override, all_templates[override]); t != "" {
|
||||
return t
|
||||
}
|
||||
}
|
||||
if t := getLookedUpTemplate(override, allTemplates[override]); t != "" {
|
||||
return t
|
||||
}
|
||||
}
|
||||
// create-bug etc are special, if we dont find it in the path
|
||||
@@ -267,9 +288,11 @@ func (c *Cli) getTemplate(name string) string {
|
||||
if strings.HasPrefix(name, "create-") {
|
||||
return getLookedUpTemplate(name, c.getTemplate("create"))
|
||||
}
|
||||
return getLookedUpTemplate(name, all_templates[name])
|
||||
return getLookedUpTemplate(name, allTemplates[name])
|
||||
}
|
||||
|
||||
// NoChangesFound is an error returned from when editing templates
|
||||
// and no modifications were made while editing
|
||||
type NoChangesFound struct{}
|
||||
|
||||
func (f NoChangesFound) Error() string {
|
||||
@@ -360,27 +383,27 @@ func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData m
|
||||
}
|
||||
|
||||
edited := make(map[string]interface{})
|
||||
if fh, err := ioutil.ReadFile(tmpFileName); err != nil {
|
||||
var data []byte
|
||||
if data, err = ioutil.ReadFile(tmpFileName); err != nil {
|
||||
log.Errorf("Failed to read tmpfile %s: %s", tmpFileName, err)
|
||||
if editing && promptYN("edit again?", true) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
if err := yaml.Unmarshal(fh, &edited); err != nil {
|
||||
log.Errorf("Failed to parse YAML: %s", err)
|
||||
if editing && promptYN("edit again?", true) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal(data, &edited); err != nil {
|
||||
log.Errorf("Failed to parse YAML: %s", err)
|
||||
if editing && promptYN("edit again?", true) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if fixed, err := yamlFixup(edited); err != nil {
|
||||
var fixed interface{}
|
||||
if fixed, err = yamlFixup(edited); err != nil {
|
||||
return err
|
||||
} else {
|
||||
edited = fixed.(map[string]interface{})
|
||||
}
|
||||
edited = fixed.(map[string]interface{})
|
||||
|
||||
// if you want to abort editing a jira issue then
|
||||
// you can add the "abort: true" flag to the document
|
||||
@@ -422,6 +445,7 @@ func (c *Cli) editTemplate(template string, tmpFilePrefix string, templateData m
|
||||
return nil
|
||||
}
|
||||
|
||||
// Browse will open up your default browser to the provided issue
|
||||
func (c *Cli) Browse(issue string) error {
|
||||
if val, ok := c.opts["browse"].(bool); ok && val {
|
||||
if runtime.GOOS == "darwin" {
|
||||
@@ -433,6 +457,7 @@ func (c *Cli) Browse(issue string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveData will write out the yaml formated --saveFile file with provided data
|
||||
func (c *Cli) SaveData(data interface{}) error {
|
||||
if val, ok := c.opts["saveFile"].(string); ok && val != "" {
|
||||
yamlWrite(val, data)
|
||||
@@ -440,33 +465,49 @@ func (c *Cli) SaveData(data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ViewIssueWorkLogs gets the worklog data for the given issue
|
||||
func (c *Cli) ViewIssueWorkLogs(issue string) (interface{}, error) {
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog", c.endpoint, issue)
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// ViewIssue will return the details for the given issue id
|
||||
func (c *Cli) ViewIssue(issue string) (interface{}, error) {
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s", c.endpoint, issue)
|
||||
if x := c.expansions(); len(x) > 0 {
|
||||
uri = fmt.Sprintf("%s?expand=%s", uri, strings.Join(x, ","))
|
||||
}
|
||||
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return data, nil
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// FindIssues will return a list of issues that match the given options.
|
||||
// If the "query" option is undefined it will generate a JQL query
|
||||
// using any/all of the provide options: project, component, assignee,
|
||||
// issuetype, watcher, reporter, sort
|
||||
// Further it will restrict the fields being extracted from the jira
|
||||
// response with the 'queryfields' option
|
||||
func (c *Cli) FindIssues() (interface{}, error) {
|
||||
var query string
|
||||
var ok bool
|
||||
// project = BAKERY and status not in (Resolved, Closed)
|
||||
if query, ok = c.opts["query"].(string); !ok {
|
||||
qbuff := bytes.NewBufferString("resolution = unresolved")
|
||||
if project, ok := c.opts["project"]; !ok {
|
||||
var project string
|
||||
if project, ok = c.opts["project"].(string); !ok {
|
||||
err := fmt.Errorf("Missing required arguments, either 'query' or 'project' are required")
|
||||
log.Errorf("%s", err)
|
||||
return nil, err
|
||||
} else {
|
||||
qbuff.WriteString(fmt.Sprintf(" AND project = '%s'", project))
|
||||
}
|
||||
qbuff.WriteString(fmt.Sprintf(" AND project = '%s'", project))
|
||||
|
||||
if component, ok := c.opts["component"]; ok {
|
||||
qbuff.WriteString(fmt.Sprintf(" AND component = '%s'", component))
|
||||
@@ -495,11 +536,9 @@ func (c *Cli) FindIssues() (interface{}, error) {
|
||||
query = qbuff.String()
|
||||
}
|
||||
|
||||
fields := make([]string, 0)
|
||||
fields := []string{"summary"}
|
||||
if qf, ok := c.opts["queryfields"].(string); ok {
|
||||
fields = strings.Split(qf, ",")
|
||||
} else {
|
||||
fields = append(fields, "summary")
|
||||
}
|
||||
|
||||
json, err := jsonEncode(map[string]interface{}{
|
||||
@@ -514,13 +553,64 @@ func (c *Cli) FindIssues() (interface{}, error) {
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/rest/api/2/search", c.endpoint)
|
||||
if data, err := responseToJson(c.post(uri, json)); err != nil {
|
||||
var data interface{}
|
||||
if data, err = responseToJSON(c.post(uri, json)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return data, nil
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// RankOrder type used to specify before/after ranking arguments to RankIssue
|
||||
type RankOrder int
|
||||
|
||||
const (
|
||||
// RANKBEFORE should be used to rank issue before the target issue
|
||||
RANKBEFORE RankOrder = iota
|
||||
// RANKAFTER should be used to rank issue after the target issue
|
||||
RANKAFTER RankOrder = iota
|
||||
)
|
||||
|
||||
// RankIssue will modify issue to have rank before or after the target issue
|
||||
func (c *Cli) RankIssue(issue, target string, order RankOrder) error {
|
||||
type RankRequest struct {
|
||||
Issues []string `json:"issues"`
|
||||
Before string `json:"rankBeforeIssue,omitempty"`
|
||||
After string `json:"rankAfterIssue,omitempty"`
|
||||
}
|
||||
req := &RankRequest{
|
||||
Issues: []string{
|
||||
issue,
|
||||
},
|
||||
}
|
||||
if order == RANKBEFORE {
|
||||
req.Before = target
|
||||
} else {
|
||||
req.After = target
|
||||
}
|
||||
|
||||
json, err := jsonEncode(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/rest/agile/1.0/issue/rank", c.endpoint)
|
||||
if c.getOptBool("dryrun", false) {
|
||||
log.Debugf("PUT: %s", json)
|
||||
log.Debugf("Dryrun mode, skipping PUT")
|
||||
return nil
|
||||
}
|
||||
resp, err := c.put(uri, json)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 204 {
|
||||
return fmt.Errorf("failed to modify issue rank: %s", resp.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOptString will extract the string from the Cli object options
|
||||
// otherwise return the provided default
|
||||
func (c *Cli) GetOptString(optName string, dflt string) string {
|
||||
return c.getOptString(optName, dflt)
|
||||
}
|
||||
@@ -528,11 +618,12 @@ func (c *Cli) GetOptString(optName string, dflt string) string {
|
||||
func (c *Cli) getOptString(optName string, dflt string) string {
|
||||
if val, ok := c.opts[optName].(string); ok {
|
||||
return val
|
||||
} else {
|
||||
return dflt
|
||||
}
|
||||
return dflt
|
||||
}
|
||||
|
||||
// GetOptBool will extract the boolean value from the Client object options
|
||||
// otherwise return the provided default\
|
||||
func (c *Cli) GetOptBool(optName string, dflt bool) bool {
|
||||
return c.getOptBool(optName, dflt)
|
||||
}
|
||||
@@ -540,14 +631,13 @@ func (c *Cli) GetOptBool(optName string, dflt bool) bool {
|
||||
func (c *Cli) getOptBool(optName string, dflt bool) bool {
|
||||
if val, ok := c.opts[optName].(bool); ok {
|
||||
return val
|
||||
} else {
|
||||
return dflt
|
||||
}
|
||||
return dflt
|
||||
}
|
||||
|
||||
// expansions returns a comma-separated list of values for field expansion
|
||||
func (c *Cli) expansions() []string {
|
||||
expansions := make([]string, 0)
|
||||
var expansions []string
|
||||
if x, ok := c.opts["expand"].(string); ok {
|
||||
expansions = strings.Split(x, ",")
|
||||
}
|
||||
|
||||
+240
-120
@@ -3,21 +3,23 @@ package jira
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Netflix-Skunkworks/go-jira/data"
|
||||
"github.com/howeyc/gopass"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/howeyc/gopass"
|
||||
"github.com/tmc/keyring"
|
||||
"gopkg.in/Netflix-Skunkworks/go-jira.v0/data"
|
||||
// "github.com/kr/pretty"
|
||||
)
|
||||
|
||||
// CmdLogin will attempt to login into jira server
|
||||
func (c *Cli) CmdLogin() error {
|
||||
uri := fmt.Sprintf("%s/rest/auth/1/session", c.endpoint)
|
||||
for true {
|
||||
for {
|
||||
req, _ := http.NewRequest("GET", uri, nil)
|
||||
user, _ := c.opts["user"].(string)
|
||||
|
||||
@@ -29,60 +31,71 @@ func (c *Cli) CmdLogin() error {
|
||||
passwd := string(pw)
|
||||
|
||||
req.SetBasicAuth(user, passwd)
|
||||
if resp, err := c.makeRequest(req); err != nil {
|
||||
|
||||
resp, err := c.makeRequest(req)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if resp.StatusCode == 403 {
|
||||
// probably got this, need to redirect the user to login manually
|
||||
// X-Authentication-Denied-Reason: CAPTCHA_CHALLENGE; login-url=https://jira/login.jsp
|
||||
if reason := resp.Header.Get("X-Authentication-Denied-Reason"); reason != "" {
|
||||
err := fmt.Errorf("Authenticaion Failed: %s", reason)
|
||||
log.Errorf("%s", err)
|
||||
return err
|
||||
}
|
||||
err := fmt.Errorf("Authentication Failed: Unknown Reason")
|
||||
}
|
||||
if resp.StatusCode == 403 {
|
||||
// probably got this, need to redirect the user to login manually
|
||||
// X-Authentication-Denied-Reason: CAPTCHA_CHALLENGE; login-url=https://jira/login.jsp
|
||||
if reason := resp.Header.Get("X-Authentication-Denied-Reason"); reason != "" {
|
||||
err := fmt.Errorf("Authenticaion Failed: %s", reason)
|
||||
log.Errorf("%s", err)
|
||||
return err
|
||||
}
|
||||
err := fmt.Errorf("Authentication Failed: Unknown Reason")
|
||||
log.Errorf("%s", err)
|
||||
return err
|
||||
|
||||
} else if resp.StatusCode == 200 {
|
||||
// https://confluence.atlassian.com/display/JIRA043/JIRA+REST+API+%28Alpha%29+Tutorial#JIRARESTAPI%28Alpha%29Tutorial-CAPTCHAs
|
||||
// probably bad password, try again
|
||||
if reason := resp.Header.Get("X-Seraph-Loginreason"); reason == "AUTHENTICATION_DENIED" {
|
||||
log.Warning("Authentication Failed: %s", reason)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
log.Warning("Login failed")
|
||||
} else if resp.StatusCode == 200 {
|
||||
// https://confluence.atlassian.com/display/JIRA043/JIRA+REST+API+%28Alpha%29+Tutorial#JIRARESTAPI%28Alpha%29Tutorial-CAPTCHAs
|
||||
// probably bad password, try again
|
||||
if reason := resp.Header.Get("X-Seraph-Loginreason"); reason == "AUTHENTICATION_DENIED" {
|
||||
log.Warning("Authentication Failed: %s", reason)
|
||||
continue
|
||||
}
|
||||
if val, ok := c.opts["password-keyring"].(bool); ok && val {
|
||||
// save password in keychain so that it can be used for subsequent http requests
|
||||
err := keyring.Set("go-jira", user, passwd)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to set password in keyring: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
} else {
|
||||
log.Warning("Login failed")
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdLogout will close any active sessions
|
||||
func (c *Cli) CmdLogout() error {
|
||||
uri := fmt.Sprintf("%s/rest/auth/1/session", c.endpoint)
|
||||
req, _ := http.NewRequest("DELETE", uri, nil)
|
||||
if resp, err := c.makeRequest(req); err != nil {
|
||||
resp, err := c.makeRequest(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode == 401 || resp.StatusCode == 204 {
|
||||
// 401 == no active session
|
||||
// 204 == successfully logged out
|
||||
} else {
|
||||
if resp.StatusCode == 401 || resp.StatusCode == 204 {
|
||||
// 401 == no active session
|
||||
// 204 == successfully logged out
|
||||
} else {
|
||||
err := fmt.Errorf("Failed to Logout: %s", err)
|
||||
return err
|
||||
}
|
||||
err := fmt.Errorf("Failed to Logout: %s", err)
|
||||
return err
|
||||
}
|
||||
log.Notice("OK")
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFields will send data from /rest/api/2/field API to "fields" template
|
||||
func (c *Cli) CmdFields() error {
|
||||
log.Debugf("fields called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/field", c.endpoint)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -90,15 +103,17 @@ func (c *Cli) CmdFields() error {
|
||||
return runTemplate(c.getTemplate("fields"), data, nil)
|
||||
}
|
||||
|
||||
// CmdList will query jira and send data to "list" template
|
||||
func (c *Cli) CmdList() error {
|
||||
log.Debugf("list called")
|
||||
if data, err := c.FindIssues(); err != nil {
|
||||
data, err := c.FindIssues()
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
return runTemplate(c.getTemplate("list"), data, nil)
|
||||
}
|
||||
return runTemplate(c.getTemplate("list"), data, nil)
|
||||
}
|
||||
|
||||
// CmdView will get issue data and send to "view" template
|
||||
func (c *Cli) CmdView(issue string) error {
|
||||
log.Debugf("view called")
|
||||
c.Browse(issue)
|
||||
@@ -109,23 +124,85 @@ func (c *Cli) CmdView(issue string) error {
|
||||
return runTemplate(c.getTemplate("view"), data, nil)
|
||||
}
|
||||
|
||||
// CmdWorklogs will get worklog data for given issue and sent to the "worklogs" template
|
||||
func (c *Cli) CmdWorklogs(issue string) error {
|
||||
log.Debugf("worklogs called")
|
||||
c.Browse(issue)
|
||||
data, err := c.ViewIssueWorkLogs(issue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runTemplate(c.getTemplate("worklogs"), data, nil)
|
||||
}
|
||||
|
||||
// CmdWorklog will attempt to add (action=add) a worklog to the given issue.
|
||||
// It will spawn the editor (unless --noedit isused) and post edited YAML
|
||||
// content as JSON to the worklog endpoint
|
||||
func (c *Cli) CmdWorklog(action string, issue string) error {
|
||||
log.Debugf("%s worklog called", action)
|
||||
c.Browse(issue)
|
||||
if action == "add" {
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/worklog", c.endpoint, issue)
|
||||
|
||||
worklogData := map[string]interface{}{
|
||||
"issue": issue,
|
||||
"comment": c.opts["comment"],
|
||||
}
|
||||
|
||||
if v, ok := c.opts["time-spent"].(string); ok {
|
||||
worklogData["timeSpent"] = v
|
||||
}
|
||||
|
||||
return c.editTemplate(
|
||||
c.getTemplate("worklog"),
|
||||
fmt.Sprintf("%s-worklog-", issue),
|
||||
worklogData,
|
||||
func(json string) error {
|
||||
if c.getOptBool("dryrun", false) {
|
||||
log.Debugf("POST: %s", json)
|
||||
log.Debugf("Dryrun mode, skipping POST")
|
||||
return nil
|
||||
}
|
||||
resp, err := c.post(uri, json)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode == 201 {
|
||||
c.Browse(issue)
|
||||
if !c.opts["quiet"].(bool) {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err = fmt.Errorf("Unexpected Response From POST")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdEdit will populate "edit" template with issue data and issue "editmeta" data.
|
||||
// Then will parse yaml template and submit data to jira.
|
||||
func (c *Cli) CmdEdit(issue string) error {
|
||||
log.Debugf("edit called")
|
||||
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/editmeta", c.endpoint, issue)
|
||||
editmeta, err := responseToJson(c.get(uri))
|
||||
editmeta, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uri = fmt.Sprintf("%s/rest/api/2/issue/%s", c.endpoint, issue)
|
||||
var issueData map[string]interface{}
|
||||
if data, err := responseToJson(c.get(uri)); err != nil {
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
issueData = data.(map[string]interface{})
|
||||
}
|
||||
|
||||
issueData := data.(map[string]interface{})
|
||||
issueData["meta"] = editmeta.(map[string]interface{})
|
||||
issueData["overrides"] = c.opts
|
||||
|
||||
@@ -150,22 +227,22 @@ func (c *Cli) CmdEdit(issue string) error {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issueData["key"], c.endpoint, issueData["key"])
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err := fmt.Errorf("Unexpected Response From PUT")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err = fmt.Errorf("Unexpected Response From PUT")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// CmdEditMeta will send issue 'edit' metadata to the "editmeta" template
|
||||
func (c *Cli) CmdEditMeta(issue string) error {
|
||||
log.Debugf("editMeta called")
|
||||
c.Browse(issue)
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/editmeta", c.endpoint, issue)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -173,11 +250,12 @@ func (c *Cli) CmdEditMeta(issue string) error {
|
||||
return runTemplate(c.getTemplate("editmeta"), data, nil)
|
||||
}
|
||||
|
||||
// CmdTransitionMeta will send available transition metadata to the "transmeta" template
|
||||
func (c *Cli) CmdTransitionMeta(issue string) error {
|
||||
log.Debugf("tranisionMeta called")
|
||||
c.Browse(issue)
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions?expand=transitions.fields", c.endpoint, issue)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -185,11 +263,12 @@ func (c *Cli) CmdTransitionMeta(issue string) error {
|
||||
return runTemplate(c.getTemplate("transmeta"), data, nil)
|
||||
}
|
||||
|
||||
// CmdIssueTypes will send issue 'create' metadata to the 'issuetypes'
|
||||
func (c *Cli) CmdIssueTypes() error {
|
||||
project := c.opts["project"].(string)
|
||||
log.Debugf("issueTypes called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s", c.endpoint, project)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -200,7 +279,7 @@ func (c *Cli) CmdIssueTypes() error {
|
||||
func (c *Cli) defaultIssueType() string {
|
||||
project := c.opts["project"].(string)
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s", c.endpoint, project)
|
||||
data, _ := responseToJson(c.get(uri))
|
||||
data, _ := responseToJSON(c.get(uri))
|
||||
issueTypeNames := make(map[string]bool)
|
||||
|
||||
if data, ok := data.(map[string]interface{}); ok {
|
||||
@@ -226,6 +305,7 @@ func (c *Cli) defaultIssueType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// CmdCreateMeta sends the 'create' metadata for the given project & issuetype and sends it to the 'createmeta' template
|
||||
func (c *Cli) CmdCreateMeta() error {
|
||||
project := c.opts["project"].(string)
|
||||
issuetype := c.getOptString("issuetype", "")
|
||||
@@ -235,7 +315,7 @@ func (c *Cli) CmdCreateMeta() error {
|
||||
|
||||
log.Debugf("createMeta called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&issuetypeNames=%s&expand=projects.issuetypes.fields", c.endpoint, project, url.QueryEscape(issuetype))
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -254,16 +334,18 @@ func (c *Cli) CmdCreateMeta() error {
|
||||
return runTemplate(c.getTemplate("createmeta"), data, nil)
|
||||
}
|
||||
|
||||
// CmdComponents sends component data for given project and sends to the "components" template
|
||||
func (c *Cli) CmdComponents(project string) error {
|
||||
log.Debugf("Components called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/project/%s/components", c.endpoint, project)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runTemplate(c.getTemplate("components"), data, nil)
|
||||
}
|
||||
|
||||
// ValidTransitions will return a list of valid transitions for given issue.
|
||||
func (c *Cli) ValidTransitions(issue string) (jiradata.Transitions, error) {
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions?expand=transitions.fields", c.endpoint, issue)
|
||||
resp, err := c.get(uri)
|
||||
@@ -284,18 +366,21 @@ func (c *Cli) ValidTransitions(issue string) (jiradata.Transitions, error) {
|
||||
return transMeta.Transitions, nil
|
||||
}
|
||||
|
||||
// CmdTransitions sends valid transtions for given issue to the "transitions" template
|
||||
func (c *Cli) CmdTransitions(issue string) error {
|
||||
log.Debugf("Transitions called")
|
||||
// FIXME this should just call ValidTransitions then pass that data to templates
|
||||
c.Browse(issue)
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions", c.endpoint, issue)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runTemplate(c.getTemplate("transitions"), data, nil)
|
||||
}
|
||||
|
||||
// CmdCreate sends the create-metadata to the "create" template for editing, then
|
||||
// will parse the edited document as YAML and submit the document to jira.
|
||||
func (c *Cli) CmdCreate() error {
|
||||
log.Debugf("create called")
|
||||
project := c.opts["project"].(string)
|
||||
@@ -305,7 +390,7 @@ func (c *Cli) CmdCreate() error {
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/createmeta?projectKeys=%s&issuetypeNames=%s&expand=projects.issuetypes.fields", c.endpoint, project, url.QueryEscape(issuetype))
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -349,43 +434,43 @@ func (c *Cli) CmdCreate() error {
|
||||
|
||||
if resp.StatusCode == 201 {
|
||||
// response: {"id":"410836","key":"PROJ-238","self":"https://jira/rest/api/2/issue/410836"}
|
||||
if json, err := responseToJson(resp, nil); err != nil {
|
||||
json, err := responseToJSON(resp, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
key := json.(map[string]interface{})["key"].(string)
|
||||
link := fmt.Sprintf("%s/browse/%s", c.endpoint, key)
|
||||
c.Browse(key)
|
||||
c.SaveData(map[string]string{
|
||||
"issue": key,
|
||||
"link": link,
|
||||
})
|
||||
if !c.opts["quiet"].(bool) {
|
||||
fmt.Printf("OK %s %s\n", key, link)
|
||||
}
|
||||
}
|
||||
key := json.(map[string]interface{})["key"].(string)
|
||||
link := fmt.Sprintf("%s/browse/%s", c.endpoint, key)
|
||||
c.Browse(key)
|
||||
c.SaveData(map[string]string{
|
||||
"issue": key,
|
||||
"link": link,
|
||||
})
|
||||
if !c.opts["quiet"].(bool) {
|
||||
fmt.Printf("OK %s %s\n", key, link)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err := fmt.Errorf("Unexpected Response From POST")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err = fmt.Errorf("Unexpected Response From POST")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdIssueLinkTypes will send the issue link type data to the "issuelinktypes" template.
|
||||
func (c *Cli) CmdIssueLinkTypes() error {
|
||||
log.Debugf("Transitions called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issueLinkType", c.endpoint)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runTemplate(c.getTemplate("issuelinktypes"), data, nil)
|
||||
}
|
||||
|
||||
// CmdBlocks will update the given issue as being "blocked" by the given blocker
|
||||
func (c *Cli) CmdBlocks(blocker string, issue string) error {
|
||||
log.Debugf("blocks called")
|
||||
|
||||
@@ -429,6 +514,8 @@ func (c *Cli) CmdBlocks(blocker string, issue string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdDups will update the given issue as being a duplicate by the given dup issue
|
||||
// and will attempt to resolve the dup issue
|
||||
func (c *Cli) CmdDups(duplicate string, issue string) error {
|
||||
log.Debugf("dups called")
|
||||
|
||||
@@ -472,6 +559,8 @@ func (c *Cli) CmdDups(duplicate string, issue string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdWatch will add the given watcher to the issue (or remove the watcher
|
||||
// given the 'remove' flag)
|
||||
func (c *Cli) CmdWatch(issue string, watcher string, remove bool) error {
|
||||
log.Debugf("watch called: watcher: %q, remove: %n", watcher, remove)
|
||||
|
||||
@@ -522,6 +611,7 @@ func (c *Cli) CmdWatch(issue string, watcher string, remove bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdVote will add or remove a vote on an issue
|
||||
func (c *Cli) CmdVote(issue string, up bool) error {
|
||||
log.Debugf("vote called, with up: %n", up)
|
||||
|
||||
@@ -565,16 +655,41 @@ func (c *Cli) CmdVote(issue string, up bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdRankAfter rank issue after target issue
|
||||
func (c *Cli) CmdRankAfter(issue, after string) error {
|
||||
err := c.RankIssue(issue, after, RANKAFTER)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !c.opts["quiet"].(bool) {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdRankBefore rank issue before target issue
|
||||
func (c *Cli) CmdRankBefore(issue, before string) error {
|
||||
err := c.RankIssue(issue, before, RANKBEFORE)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !c.opts["quiet"].(bool) {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdTransition will move state of the given issue to the given transtion
|
||||
func (c *Cli) CmdTransition(issue string, trans string) error {
|
||||
log.Debugf("transition called")
|
||||
uri := fmt.Sprintf("%s/rest/api/2/issue/%s/transitions?expand=transitions.fields", c.endpoint, issue)
|
||||
data, err := responseToJson(c.get(uri))
|
||||
data, err := responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
transitions := data.(map[string]interface{})["transitions"].([]interface{})
|
||||
var transId, transName string
|
||||
var transID, transName string
|
||||
var transMeta map[string]interface{}
|
||||
found := make([]string, 0, len(transitions))
|
||||
for _, transition := range transitions {
|
||||
@@ -583,11 +698,14 @@ func (c *Cli) CmdTransition(issue string, trans string) error {
|
||||
found = append(found, name)
|
||||
if strings.Contains(strings.ToLower(name), strings.ToLower(trans)) {
|
||||
transName = name
|
||||
transId = id
|
||||
transID = id
|
||||
transMeta = transition.(map[string]interface{})
|
||||
if strings.ToLower(name) == strings.ToLower(trans) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if transId == "" {
|
||||
if transID == "" {
|
||||
err := fmt.Errorf("Invalid Transition '%s', Available: %s", trans, strings.Join(found, ", "))
|
||||
log.Debugf("%s", err)
|
||||
return err
|
||||
@@ -620,12 +738,11 @@ func (c *Cli) CmdTransition(issue string, trans string) error {
|
||||
}
|
||||
|
||||
uri = fmt.Sprintf("%s/rest/api/2/issue/%s", c.endpoint, issue)
|
||||
var issueData map[string]interface{}
|
||||
if data, err := responseToJson(c.get(uri)); err != nil {
|
||||
data, err = responseToJSON(c.get(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
issueData = data.(map[string]interface{})
|
||||
}
|
||||
issueData := data.(map[string]interface{})
|
||||
issueData["meta"] = transMeta
|
||||
if c.GetOptString("defaultResolution", "") == "" {
|
||||
// .meta.fields.resolution.allowedValues
|
||||
@@ -648,7 +765,7 @@ func (c *Cli) CmdTransition(issue string, trans string) error {
|
||||
issueData["overrides"] = c.opts
|
||||
issueData["transition"] = map[string]interface{}{
|
||||
"name": transName,
|
||||
"id": transId,
|
||||
"id": transID,
|
||||
}
|
||||
return c.editTemplate(
|
||||
c.getTemplate("transition"),
|
||||
@@ -658,6 +775,8 @@ func (c *Cli) CmdTransition(issue string, trans string) error {
|
||||
)
|
||||
}
|
||||
|
||||
// CmdComment will open up editor with "comment" template and submit
|
||||
// YAML output to jira
|
||||
func (c *Cli) CmdComment(issue string) error {
|
||||
log.Debugf("comment called")
|
||||
|
||||
@@ -679,13 +798,12 @@ func (c *Cli) CmdComment(issue string) error {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err := fmt.Errorf("Unexpected Response From POST")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err = fmt.Errorf("Unexpected Response From POST")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
|
||||
if comment, ok := c.opts["comment"]; ok && comment != "" {
|
||||
@@ -696,24 +814,23 @@ func (c *Cli) CmdComment(issue string) error {
|
||||
return err
|
||||
}
|
||||
return handlePost(json)
|
||||
} else {
|
||||
return c.editTemplate(
|
||||
c.getTemplate("comment"),
|
||||
fmt.Sprintf("%s-create-", issue),
|
||||
map[string]interface{}{},
|
||||
handlePost,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
return c.editTemplate(
|
||||
c.getTemplate("comment"),
|
||||
fmt.Sprintf("%s-create-", issue),
|
||||
map[string]interface{}{},
|
||||
handlePost,
|
||||
)
|
||||
}
|
||||
|
||||
// CmdComponent will add a new component to given project
|
||||
func (c *Cli) CmdComponent(action string, project string, name string, desc string, lead string) error {
|
||||
log.Debugf("component called")
|
||||
|
||||
switch action {
|
||||
case "add":
|
||||
default:
|
||||
return errors.New(fmt.Sprintf("CmdComponent: %q is not a valid action", action))
|
||||
return fmt.Errorf("CmdComponent: %q is not a valid action", action)
|
||||
}
|
||||
|
||||
json, err := jsonEncode(map[string]interface{}{
|
||||
@@ -750,6 +867,7 @@ func (c *Cli) CmdComponent(action string, project string, name string, desc stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdLabels will add, remove or set labels on a given issue
|
||||
func (c *Cli) CmdLabels(action string, issue string, labels []string) error {
|
||||
log.Debugf("label called")
|
||||
|
||||
@@ -775,23 +893,22 @@ func (c *Cli) CmdLabels(action string, issue string, labels []string) error {
|
||||
fmt.Printf("OK %s %s/browse/%s\n", issue, c.endpoint, issue)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err := fmt.Errorf("Unexpected Response From PUT")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
logBuffer := bytes.NewBuffer(make([]byte, 0))
|
||||
resp.Write(logBuffer)
|
||||
err = fmt.Errorf("Unexpected Response From PUT")
|
||||
log.Errorf("%s:\n%s", err, logBuffer)
|
||||
return err
|
||||
}
|
||||
|
||||
var labels_json string
|
||||
var labelsJSON string
|
||||
var err error
|
||||
if action == "set" {
|
||||
labelsActions := make([]map[string][]string, 1)
|
||||
labelsActions[0] = map[string][]string{
|
||||
"set": labels,
|
||||
}
|
||||
labels_json, err = jsonEncode(map[string]interface{}{
|
||||
labelsJSON, err = jsonEncode(map[string]interface{}{
|
||||
"labels": labelsActions,
|
||||
})
|
||||
} else {
|
||||
@@ -802,18 +919,19 @@ func (c *Cli) CmdLabels(action string, issue string, labels []string) error {
|
||||
}
|
||||
labelsActions[i] = labelActionMap
|
||||
}
|
||||
labels_json, err = jsonEncode(map[string]interface{}{
|
||||
labelsJSON, err = jsonEncode(map[string]interface{}{
|
||||
"labels": labelsActions,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json := fmt.Sprintf("{ \"update\": %s }", labels_json)
|
||||
json := fmt.Sprintf("{ \"update\": %s }", labelsJSON)
|
||||
return handlePut(json)
|
||||
|
||||
}
|
||||
|
||||
// CmdAssign will assign the given user to be the owner of the given issue
|
||||
func (c *Cli) CmdAssign(issue string, user string) error {
|
||||
log.Debugf("assign called")
|
||||
|
||||
@@ -849,13 +967,14 @@ func (c *Cli) CmdAssign(issue string, user string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdExportTemplates will export the default templates to the template directory.
|
||||
func (c *Cli) CmdExportTemplates() error {
|
||||
dir := c.opts["directory"].(string)
|
||||
if err := mkdir(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for name, template := range all_templates {
|
||||
for name, template := range allTemplates {
|
||||
if wanted, ok := c.opts["template"]; ok && wanted != name {
|
||||
continue
|
||||
}
|
||||
@@ -864,18 +983,19 @@ func (c *Cli) CmdExportTemplates() error {
|
||||
log.Warning("Skipping %s, already exists", templateFile)
|
||||
continue
|
||||
}
|
||||
if fh, err := os.OpenFile(templateFile, os.O_WRONLY|os.O_CREATE, 0644); err != nil {
|
||||
fh, err := os.OpenFile(templateFile, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to open %s for writing: %s", templateFile, err)
|
||||
return err
|
||||
} else {
|
||||
defer fh.Close()
|
||||
log.Noticef("Creating %s", templateFile)
|
||||
fh.Write([]byte(template))
|
||||
}
|
||||
defer fh.Close()
|
||||
log.Noticef("Creating %s", templateFile)
|
||||
fh.Write([]byte(template))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdRequest will use the given uri to make a request and potentially send provided content.
|
||||
func (c *Cli) CmdRequest(uri, content string) (err error) {
|
||||
log.Debugf("request called")
|
||||
|
||||
@@ -886,11 +1006,11 @@ func (c *Cli) CmdRequest(uri, content string) (err error) {
|
||||
method := strings.ToUpper(c.opts["method"].(string))
|
||||
var data interface{}
|
||||
if method == "GET" {
|
||||
data, err = responseToJson(c.get(uri))
|
||||
data, err = responseToJSON(c.get(uri))
|
||||
} else if method == "POST" {
|
||||
data, err = responseToJson(c.post(uri, content))
|
||||
data, err = responseToJSON(c.post(uri, content))
|
||||
} else if method == "PUT" {
|
||||
data, err = responseToJson(c.put(uri, content))
|
||||
data, err = responseToJSON(c.put(uri, content))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// AllowedValues defined from schema:
|
||||
// {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// }
|
||||
type AllowedValues []interface{}
|
||||
@@ -0,0 +1,87 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FieldMeta defined from schema:
|
||||
// {
|
||||
// "title": "Field Meta",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "allowedValues": {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// },
|
||||
// "autoCompleteUrl": {
|
||||
// "title": "autoCompleteUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "hasDefaultValue": {
|
||||
// "title": "hasDefaultValue",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "operations": {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// },
|
||||
// "required": {
|
||||
// "title": "required",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "schema": {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type FieldMeta struct {
|
||||
AllowedValues AllowedValues `json:"allowedValues,omitempty" yaml:"allowedValues,omitempty"`
|
||||
AutoCompleteURL string `json:"autoCompleteUrl,omitempty" yaml:"autoCompleteUrl,omitempty"`
|
||||
HasDefaultValue bool `json:"hasDefaultValue,omitempty" yaml:"hasDefaultValue,omitempty"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Operations Operations `json:"operations,omitempty" yaml:"operations,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Schema *JSONType `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FieldMetaMap defined from schema:
|
||||
// {
|
||||
// "title": "fields",
|
||||
// "type": "object",
|
||||
// "patternProperties": {
|
||||
// ".+": {
|
||||
// "title": "Field Meta",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "allowedValues": {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// },
|
||||
// "autoCompleteUrl": {
|
||||
// "title": "autoCompleteUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "hasDefaultValue": {
|
||||
// "title": "hasDefaultValue",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "operations": {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// },
|
||||
// "required": {
|
||||
// "title": "required",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "schema": {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type FieldMetaMap map[string]*FieldMeta
|
||||
@@ -0,0 +1,46 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// JSONType defined from schema:
|
||||
// {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type JSONType struct {
|
||||
Custom string `json:"custom,omitempty" yaml:"custom,omitempty"`
|
||||
CustomID int `json:"customId,omitempty" yaml:"customId,omitempty"`
|
||||
Items string `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
System string `json:"system,omitempty" yaml:"system,omitempty"`
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Operations defined from schema:
|
||||
// {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
type Operations []string
|
||||
@@ -0,0 +1,78 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Status defined from schema:
|
||||
// {
|
||||
// "title": "Status",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "description": {
|
||||
// "title": "description",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "iconUrl": {
|
||||
// "title": "iconUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "statusCategory": {
|
||||
// "title": "Status Category",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "colorName": {
|
||||
// "title": "colorName",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "statusColor": {
|
||||
// "title": "statusColor",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type Status struct {
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
IconURL string `json:"iconUrl,omitempty" yaml:"iconUrl,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
||||
StatusCategory *StatusCategory `json:"statusCategory,omitempty" yaml:"statusCategory,omitempty"`
|
||||
StatusColor string `json:"statusColor,omitempty" yaml:"statusColor,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// StatusCategory defined from schema:
|
||||
// {
|
||||
// "title": "Status Category",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "colorName": {
|
||||
// "title": "colorName",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type StatusCategory struct {
|
||||
ColorName string `json:"colorName,omitempty" yaml:"colorName,omitempty"`
|
||||
ID int `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Self string `json:"self,omitempty" yaml:"self,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Transition defined from schema:
|
||||
// {
|
||||
// "title": "Transition",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "expand": {
|
||||
// "title": "expand",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "fields": {
|
||||
// "title": "fields",
|
||||
// "type": "object",
|
||||
// "patternProperties": {
|
||||
// ".+": {
|
||||
// "title": "Field Meta",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "allowedValues": {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// },
|
||||
// "autoCompleteUrl": {
|
||||
// "title": "autoCompleteUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "hasDefaultValue": {
|
||||
// "title": "hasDefaultValue",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "operations": {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// },
|
||||
// "required": {
|
||||
// "title": "required",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "schema": {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "hasScreen": {
|
||||
// "title": "hasScreen",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "to": {
|
||||
// "title": "Status",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "description": {
|
||||
// "title": "description",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "iconUrl": {
|
||||
// "title": "iconUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "statusCategory": {
|
||||
// "title": "Status Category",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "colorName": {
|
||||
// "title": "colorName",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "statusColor": {
|
||||
// "title": "statusColor",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type Transition struct {
|
||||
Expand string `json:"expand,omitempty" yaml:"expand,omitempty"`
|
||||
Fields FieldMetaMap `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||
HasScreen bool `json:"hasScreen,omitempty" yaml:"hasScreen,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
To *Status `json:"to,omitempty" yaml:"to,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Transitions defined from schema:
|
||||
// {
|
||||
// "title": "transitions",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "title": "Transition",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "expand": {
|
||||
// "title": "expand",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "fields": {
|
||||
// "title": "fields",
|
||||
// "type": "object",
|
||||
// "patternProperties": {
|
||||
// ".+": {
|
||||
// "title": "Field Meta",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "allowedValues": {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// },
|
||||
// "autoCompleteUrl": {
|
||||
// "title": "autoCompleteUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "hasDefaultValue": {
|
||||
// "title": "hasDefaultValue",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "operations": {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// },
|
||||
// "required": {
|
||||
// "title": "required",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "schema": {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "hasScreen": {
|
||||
// "title": "hasScreen",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "to": {
|
||||
// "title": "Status",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "description": {
|
||||
// "title": "description",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "iconUrl": {
|
||||
// "title": "iconUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "statusCategory": {
|
||||
// "title": "Status Category",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "colorName": {
|
||||
// "title": "colorName",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "statusColor": {
|
||||
// "title": "statusColor",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type Transitions []*Transition
|
||||
@@ -0,0 +1,18 @@
|
||||
package jiradata
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Find will search the transitions for one that matches
|
||||
// the given name. It will return a valid trantion that matches
|
||||
// or nil
|
||||
func (t Transitions) Find(name string) *Transition {
|
||||
name = strings.ToLower(name)
|
||||
for _, trans := range t {
|
||||
if strings.Contains(strings.ToLower(trans.Name), name) {
|
||||
return trans
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package jiradata
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This Code is Generated by SlipScheme Project:
|
||||
// https://github.com/coryb/slipscheme
|
||||
//
|
||||
// Generated with command:
|
||||
// slipscheme -pkg jiradata -overwrite ../schemas/TransitionsMeta.json
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT EDIT //
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TransitionsMeta defined from schema:
|
||||
// {
|
||||
// "title": "Transitions Meta",
|
||||
// "id": "https://docs.atlassian.com/jira/REST/schema/transitions-meta#",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "expand": {
|
||||
// "title": "expand",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "transitions": {
|
||||
// "title": "transitions",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "title": "Transition",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "expand": {
|
||||
// "title": "expand",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "fields": {
|
||||
// "title": "fields",
|
||||
// "type": "object",
|
||||
// "patternProperties": {
|
||||
// ".+": {
|
||||
// "title": "Field Meta",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "allowedValues": {
|
||||
// "title": "allowedValues",
|
||||
// "type": "array",
|
||||
// "items": {}
|
||||
// },
|
||||
// "autoCompleteUrl": {
|
||||
// "title": "autoCompleteUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "hasDefaultValue": {
|
||||
// "title": "hasDefaultValue",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "operations": {
|
||||
// "title": "operations",
|
||||
// "type": "array",
|
||||
// "items": {
|
||||
// "type": "string"
|
||||
// }
|
||||
// },
|
||||
// "required": {
|
||||
// "title": "required",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "schema": {
|
||||
// "title": "Json Type",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "custom": {
|
||||
// "title": "custom",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "customId": {
|
||||
// "title": "customId",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "items": {
|
||||
// "title": "items",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "system": {
|
||||
// "title": "system",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "type": {
|
||||
// "title": "type",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "hasScreen": {
|
||||
// "title": "hasScreen",
|
||||
// "type": "boolean"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "to": {
|
||||
// "title": "Status",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "description": {
|
||||
// "title": "description",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "iconUrl": {
|
||||
// "title": "iconUrl",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "statusCategory": {
|
||||
// "title": "Status Category",
|
||||
// "type": "object",
|
||||
// "properties": {
|
||||
// "colorName": {
|
||||
// "title": "colorName",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "id": {
|
||||
// "title": "id",
|
||||
// "type": "integer"
|
||||
// },
|
||||
// "key": {
|
||||
// "title": "key",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "name": {
|
||||
// "title": "name",
|
||||
// "type": "string"
|
||||
// },
|
||||
// "self": {
|
||||
// "title": "self",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "statusColor": {
|
||||
// "title": "statusColor",
|
||||
// "type": "string"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
type TransitionsMeta struct {
|
||||
Expand string `json:"expand,omitempty" yaml:"expand,omitempty"`
|
||||
Transitions Transitions `json:"transitions,omitempty" yaml:"transitions,omitempty"`
|
||||
}
|
||||
+30
-1
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/Netflix-Skunkworks/go-jira"
|
||||
"gopkg.in/Netflix-Skunkworks/go-jira.v0"
|
||||
"github.com/coryb/optigo"
|
||||
"gopkg.in/coryb/yaml.v2"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
@@ -56,11 +56,14 @@ func main() {
|
||||
Usage:
|
||||
jira (ls|list) <Query Options>
|
||||
jira view ISSUE
|
||||
jira worklog ISSUE
|
||||
jira add worklog ISSUE <Worklog Options>
|
||||
jira edit [--noedit] <Edit Options> [ISSUE | <Query Options>]
|
||||
jira create [--noedit] [-p PROJECT] <Create Options>
|
||||
jira DUPLICATE dups ISSUE
|
||||
jira BLOCKER blocks ISSUE
|
||||
jira vote ISSUE [--down]
|
||||
jira rank ISSUE (after|before) ISSUE
|
||||
jira watch ISSUE [-w WATCHER] [--remove]
|
||||
jira (trans|transition) TRANSITION ISSUE [--noedit] <Edit Options>
|
||||
jira ack ISSUE [--edit] <Edit Options>
|
||||
@@ -101,6 +104,7 @@ General Options:
|
||||
-t --template=FILE Template file to use for output/editing
|
||||
-u --user=USER Username to use for authenticaion (default: %s)
|
||||
-v --verbose Increase output logging
|
||||
--unixproxy=PATH Path for a unix-socket proxy (eg., --unixproxy /tmp/proxy.sock)
|
||||
--version Print version
|
||||
|
||||
Query Options:
|
||||
@@ -125,6 +129,10 @@ Create Options:
|
||||
-m --comment=COMMENT Comment message for transition
|
||||
-o --override=KEY=VAL Set custom key/value pairs
|
||||
|
||||
Worklog Options:
|
||||
-T --time-spent=TIMESPENT Time spent working on issue
|
||||
-m --comment=COMMENT Comment message for worklog
|
||||
|
||||
Command Options:
|
||||
-d --directory=DIR Directory to export templates to (default: %s)
|
||||
`, user, defaultQueryFields, defaultMaxResults, defaultSort, user, fmt.Sprintf("%s/.jira.d/templates", home))
|
||||
@@ -177,6 +185,9 @@ Command Options:
|
||||
"req": "request",
|
||||
"request": "request",
|
||||
"vote": "vote",
|
||||
"rank": "rank",
|
||||
"worklog": "worklog",
|
||||
"addworklog": "addworklog",
|
||||
}
|
||||
|
||||
defaults := map[string]interface{}{
|
||||
@@ -229,7 +240,9 @@ Command Options:
|
||||
"d|dir|directory=s": setopt,
|
||||
"M|method=s": setopt,
|
||||
"S|saveFile=s": setopt,
|
||||
"T|time-spent=s": setopt,
|
||||
"Q|quiet": setopt,
|
||||
"unixproxy": setopt,
|
||||
"down": setopt,
|
||||
})
|
||||
|
||||
@@ -482,6 +495,15 @@ Command Options:
|
||||
case "view":
|
||||
requireArgs(1)
|
||||
err = c.CmdView(args[0])
|
||||
case "worklog":
|
||||
if len(args) > 0 && args[0] == "add" {
|
||||
setEditing(true)
|
||||
requireArgs(2)
|
||||
err = c.CmdWorklog(args[0], args[1])
|
||||
} else {
|
||||
requireArgs(1)
|
||||
err = c.CmdWorklogs(args[0])
|
||||
}
|
||||
case "vote":
|
||||
requireArgs(1)
|
||||
if val, ok := opts["down"]; ok {
|
||||
@@ -489,6 +511,13 @@ Command Options:
|
||||
} else {
|
||||
err = c.CmdVote(args[0], true)
|
||||
}
|
||||
case "rank":
|
||||
requireArgs(3)
|
||||
if args[1] == "after" {
|
||||
err = c.CmdRankAfter(args[0], args[2])
|
||||
} else {
|
||||
err = c.CmdRankBefore(args[0], args[2])
|
||||
}
|
||||
case "request":
|
||||
requireArgs(1)
|
||||
data := ""
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
!src/
|
||||
Regular → Executable
+9
-2
@@ -1,2 +1,9 @@
|
||||
endpoint: http://localhost:8080
|
||||
user: gojira
|
||||
#!/bin/sh
|
||||
if [ -z "$JIRACLOUD" ]; then
|
||||
echo endpoint: http://localhost:8080
|
||||
echo user: gojira
|
||||
echo password-keyring: true
|
||||
else
|
||||
echo endpoint: https://go-jira.atlassian.net
|
||||
echo user: gojira@example.com
|
||||
fi
|
||||
|
||||
+19
-11
@@ -3,28 +3,36 @@ eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
|
||||
cd $(dirname $0)
|
||||
jira="../jira --user admin"
|
||||
|
||||
SKIP test -n "$JIRACLOUD" # using Jira Cloud at go-jira.atlassian.net
|
||||
PLAN 15
|
||||
|
||||
# clean out any old containers
|
||||
RUNS sh -c "docker rm -f go-jira-test || true"
|
||||
docker rm -f go-jira-test
|
||||
|
||||
# start newt jira service
|
||||
RUNS docker run --detach --name go-jira-test --publish 8080:8080 go-jira-test:latest
|
||||
RUNS docker build . -t go-jira-test
|
||||
|
||||
# wait a few seconds for it to bind to port 8080
|
||||
RUNS sleep 10
|
||||
mkdir -p $(pwd)/.maven-cache
|
||||
|
||||
# wait for healthchecks to pass, curl will retry 60 times over 1 min waiting
|
||||
RUNS curl -q -L --retry 60 --retry-delay 1 -f -s "http://localhost:8080/rest/api/2/serverInfo?doHealthCheck=1"
|
||||
# start newt jira service, cache the users m2 directory to make startup faster
|
||||
RUNS docker run --detach -v $(pwd)/.maven-cache:/root/.m2/repository --name go-jira-test --publish 8080:8080 go-jira-test:latest
|
||||
|
||||
# wait for docker service to get started
|
||||
RUNS sleep 5
|
||||
|
||||
echo "# Waiting for jira service to be listening on port 8080"
|
||||
docker exec -i go-jira-test tail -f screenlog.0 | grep -m 1 'jira started successfully' | sed 's/^/# /'
|
||||
|
||||
# wait for healthchecks to pass, curl will retry 900 times over 15 min waiting
|
||||
RUNS curl -q -L --retry 900 --retry-delay 1 -f -s "http://localhost:8080/rest/api/2/serverInfo?doHealthCheck=1"
|
||||
|
||||
# login to jira as admin user
|
||||
echo "admin123" | RUNS $jira login
|
||||
RUNS $jira login
|
||||
|
||||
# create gojira user
|
||||
RUNS $jira req -M POST /rest/api/2/user '{"name":"gojira","password":"gojira123","emailAddress":"gojira@example.com","displayName":"Go Jira"}'
|
||||
RUNS $jira req -M POST /rest/api/2/user '{"name":"gojira","password":"gojira123","emailAddress":"gojira@example.com","displayName":"GoJira"}'
|
||||
|
||||
# create mojira user (need secondary user for voting)
|
||||
RUNS $jira req -M POST /rest/api/2/user '{"name":"mojira","password":"mojira123","emailAddress":"mojira@example.com","displayName":"Mo Jira"}'
|
||||
# create mothra user (need secondary user for voting)
|
||||
RUNS $jira req -M POST /rest/api/2/user '{"name":"mothra","password":"mothra123","emailAddress":"mothra@example.com","displayName":"Mothra"}'
|
||||
|
||||
# create SCRUM softwareproject
|
||||
RUNS $jira req -M POST /rest/api/2/project '{"key":"SCRUM","name":"Scrum","projectTypeKey":"software","projectTemplateKey":"com.pyxis.greenhopper.jira:gh-scrum-template","lead":"gojira"}'
|
||||
|
||||
+3
-1
@@ -3,6 +3,8 @@ eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
|
||||
cd $(dirname $0)
|
||||
jira=../jira
|
||||
|
||||
SKIP test -n "$JIRACLOUD" # using Jira Cloud at go-jira.atlassian.net
|
||||
|
||||
PLAN 7
|
||||
|
||||
###############################################################################
|
||||
@@ -24,6 +26,6 @@ echo "gojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira req /rest/auth/1/session </dev/null
|
||||
GREP '"name": "gojira"'
|
||||
GREP '"self": "http://localhost:8080/rest/api/latest/user?username=gojira"'
|
||||
GREP "\"self\": \"$ENDPOINT/rest/api/latest/user?username=gojira\""
|
||||
|
||||
|
||||
|
||||
+53
-35
@@ -4,23 +4,28 @@ cd $(dirname $0)
|
||||
jira="../jira --project BASIC"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
PLAN 84
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
($jira ls | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
|
||||
PLAN 86
|
||||
|
||||
# reset login
|
||||
RUNS $jira logout
|
||||
echo "gojira123" | RUNS $jira login
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
($jira ls | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
|
||||
|
||||
###############################################################################
|
||||
## Create an issue
|
||||
###############################################################################
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
RUNS $jira -v -v -v create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -52,6 +57,19 @@ DIFF <<EOF
|
||||
$(printf %-12s $issue:) summary
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## List all issues, using the table template
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira ls --template table
|
||||
DIFF <<EOF
|
||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
|
||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||
| $(printf %-14s $issue) | summary | Medium | To Do | a minute | gojira | gojira |
|
||||
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Try to close the issue, bug Basic projects do not allow that state
|
||||
###############################################################################
|
||||
@@ -67,7 +85,7 @@ EOF
|
||||
|
||||
RUNS $jira done $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -85,13 +103,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -102,8 +120,8 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -140,7 +158,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -149,7 +167,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -181,13 +199,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -195,7 +213,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -222,7 +240,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -244,19 +262,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -265,7 +283,7 @@ EOF
|
||||
|
||||
RUNS $jira trans "In Progress" $blocker --noedit
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -274,7 +292,7 @@ EOF
|
||||
|
||||
RUNS $jira todo $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -283,7 +301,7 @@ EOF
|
||||
|
||||
RUNS $jira trans "review" $blocker --noedit
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -292,7 +310,7 @@ EOF
|
||||
|
||||
RUNS $jira todo $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -301,7 +319,7 @@ EOF
|
||||
|
||||
RUNS $jira prog $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -310,7 +328,7 @@ EOF
|
||||
|
||||
RUNS $jira done $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -341,7 +359,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -362,7 +380,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -373,7 +391,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -401,7 +419,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -429,7 +447,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -452,12 +470,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -468,7 +486,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: BASIC
|
||||
issuetype: Bug
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -485,7 +503,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
|
||||
cd $(dirname $0)
|
||||
jira="../jira --project BASIC"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 8
|
||||
|
||||
# reset login
|
||||
RUNS $jira logout
|
||||
echo "gojira123" | RUNS $jira login
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
($jira ls | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
|
||||
|
||||
###############################################################################
|
||||
## Create an issue
|
||||
###############################################################################
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Add a worklog to an issue
|
||||
###############################################################################
|
||||
RUNS $jira add worklog $issue --comment "work is hard" --time-spent "1h 12m" --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify worklog got added to issue
|
||||
###############################################################################
|
||||
RUNS $jira worklog $issue
|
||||
DIFF <<EOF
|
||||
- # gojira, a minute ago
|
||||
comment: work is hard
|
||||
timeSpent: 1h 12m
|
||||
|
||||
EOF
|
||||
+35
-30
@@ -4,6 +4,11 @@ cd $(dirname $0)
|
||||
jira="../jira --project SCRUM"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 84
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
@@ -20,7 +25,7 @@ RUNS $jira create -o summary=summary -o description=description --noedit --saveF
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -67,7 +72,7 @@ EOF
|
||||
|
||||
RUNS $jira done $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -85,13 +90,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -102,8 +107,8 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -140,7 +145,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -149,7 +154,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -181,13 +186,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -195,7 +200,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -222,7 +227,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -244,19 +249,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -265,7 +270,7 @@ EOF
|
||||
|
||||
RUNS $jira trans "In Progress" $blocker --noedit
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -274,7 +279,7 @@ EOF
|
||||
|
||||
RUNS $jira todo $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -292,7 +297,7 @@ EOF
|
||||
|
||||
RUNS $jira todo $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -301,7 +306,7 @@ EOF
|
||||
|
||||
RUNS $jira prog $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -310,7 +315,7 @@ EOF
|
||||
|
||||
RUNS $jira done $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -341,7 +346,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -362,7 +367,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -373,7 +378,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -401,7 +406,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -429,7 +434,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -452,12 +457,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -468,7 +473,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: SCRUM
|
||||
issuetype: Bug
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -485,7 +490,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
|
||||
+35
-30
@@ -4,6 +4,11 @@ cd $(dirname $0)
|
||||
jira="../jira --project KANBAN"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 86
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
@@ -20,7 +25,7 @@ RUNS $jira create -o summary=summary -o description=description --noedit --saveF
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -67,7 +72,7 @@ EOF
|
||||
|
||||
RUNS $jira done $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -85,13 +90,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -102,8 +107,8 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -140,7 +145,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -149,7 +154,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -181,13 +186,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -195,7 +200,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -222,7 +227,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -244,19 +249,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -265,7 +270,7 @@ EOF
|
||||
|
||||
RUNS $jira trans "In Progress" $blocker --noedit
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -283,7 +288,7 @@ EOF
|
||||
|
||||
RUNS $jira backlog $blocker --noedit
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -301,7 +306,7 @@ EOF
|
||||
|
||||
RUNS $jira backlog $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -310,7 +315,7 @@ EOF
|
||||
|
||||
RUNS $jira prog $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -319,7 +324,7 @@ EOF
|
||||
|
||||
RUNS $jira done $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -350,7 +355,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -371,7 +376,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -382,7 +387,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -410,7 +415,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -438,7 +443,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -461,12 +466,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -477,7 +482,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: KANBAN
|
||||
issuetype: Bug
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[Backlog]
|
||||
@@ -494,7 +499,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
|
||||
+38
-33
@@ -4,6 +4,11 @@ cd $(dirname $0)
|
||||
jira="../jira --project PROJECT"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 84
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
@@ -20,7 +25,7 @@ RUNS $jira create -o summary=summary -o description=description --noedit --saveF
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -67,7 +72,7 @@ EOF
|
||||
|
||||
RUNS $jira done $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -85,13 +90,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -102,8 +107,8 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -140,7 +145,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -149,7 +154,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -181,13 +186,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -195,7 +200,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -222,7 +227,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -244,19 +249,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -279,12 +284,12 @@ ERROR Invalid Transition 'review', Available: Start Progress, Done
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Set it to "Start Progress" and verify that assignee is set to mojira
|
||||
## Set it to "Start Progress" and verify that assignee is set to mothra
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira start $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -295,7 +300,7 @@ status: In Progress
|
||||
summary: blocks
|
||||
project: PROJECT
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -311,7 +316,7 @@ EOF
|
||||
|
||||
RUNS $jira stop $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
|
||||
@@ -321,7 +326,7 @@ EOF
|
||||
|
||||
RUNS $jira done $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -352,7 +357,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -373,7 +378,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -384,7 +389,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -395,7 +400,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: PROJECT
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -412,7 +417,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -423,7 +428,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: PROJECT
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -440,7 +445,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -451,7 +456,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: PROJECT
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -468,7 +473,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -491,12 +496,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -507,7 +512,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: PROJECT
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
|
||||
+35
-30
@@ -4,6 +4,11 @@ cd $(dirname $0)
|
||||
jira="../jira --project PROCESS"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 84
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
@@ -21,7 +26,7 @@ RUNS $jira create -o summary=summary -o description=description --noedit --saveF
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -69,13 +74,13 @@ EOF
|
||||
|
||||
RUNS $jira start $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
|
||||
RUNS $jira stop $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -93,13 +98,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -112,9 +117,9 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -151,7 +156,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -160,7 +165,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -192,13 +197,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -206,7 +211,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -233,7 +238,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -255,19 +260,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -295,7 +300,7 @@ EOF
|
||||
|
||||
RUNS $jira start $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -304,7 +309,7 @@ EOF
|
||||
|
||||
RUNS $jira stop $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
|
||||
@@ -314,7 +319,7 @@ EOF
|
||||
|
||||
RUNS $jira reopen $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -345,7 +350,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -366,7 +371,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -377,7 +382,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -405,7 +410,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -433,7 +438,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -456,12 +461,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -472,7 +477,7 @@ status: Open
|
||||
summary: blocks
|
||||
project: PROCESS
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[Open]
|
||||
@@ -489,7 +494,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
|
||||
+31
-26
@@ -4,6 +4,11 @@ cd $(dirname $0)
|
||||
jira="../jira --project TASK"
|
||||
export JIRA_LOG_FORMAT="%{level:-5s} %{message}"
|
||||
|
||||
ENDPOINT="http://localhost:8080"
|
||||
if [ -n "$JIRACLOUD" ]; then
|
||||
ENDPOINT="https://go-jira.atlassian.net"
|
||||
fi
|
||||
|
||||
PLAN 82
|
||||
|
||||
# cleanup from previous failed test executions
|
||||
@@ -20,7 +25,7 @@ RUNS $jira create -o summary=summary -o description=description --noedit --saveF
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -67,7 +72,7 @@ EOF
|
||||
|
||||
RUNS $jira done $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -85,13 +90,13 @@ EOF
|
||||
RUNS $jira create -o summary=summary -o description=description --noedit --saveFile issue.props
|
||||
issue=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira create -o summary=dup -o description=dup --noedit --saveFile issue.props
|
||||
dup=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -104,8 +109,8 @@ EOF
|
||||
|
||||
RUNS $jira $dup dups $issue --noedit
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $dup http://localhost:8080/browse/$dup
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
OK $dup $ENDPOINT/browse/$dup
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -142,7 +147,7 @@ EOF
|
||||
RUNS $jira create -o summary=blocks -o description=blocks --noedit --saveFile issue.props
|
||||
blocker=$(awk '/issue/{print $2}' issue.props)
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -151,7 +156,7 @@ EOF
|
||||
|
||||
RUNS $jira $blocker blocks $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -183,13 +188,13 @@ $(printf %-12s $blocker:) blocks
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
# reset login for mojira for voting
|
||||
# reset login for mothra for voting
|
||||
###############################################################################
|
||||
|
||||
jira="$jira --user mojira"
|
||||
jira="$jira --user mothra"
|
||||
|
||||
RUNS $jira logout
|
||||
echo "mojira123" | RUNS $jira login
|
||||
echo "mothra123" | RUNS $jira login
|
||||
|
||||
###############################################################################
|
||||
## vote for main issue, verify it shows when viewing the issue
|
||||
@@ -197,7 +202,7 @@ echo "mojira123" | RUNS $jira login
|
||||
|
||||
RUNS $jira vote $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -224,7 +229,7 @@ EOF
|
||||
|
||||
RUNS $jira vote $issue --down
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -246,19 +251,19 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## set mojira user as watcher to issue and verify from REST api
|
||||
## set mothra user as watcher to issue and verify from REST api
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira watch $issue
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
# FIXME we probably need a watchers command to wrap this?
|
||||
RUNS sh -c "$jira req /rest/api/2/issue/$issue/watchers | jq -r .watchers[].name"
|
||||
DIFF <<EOF
|
||||
gojira
|
||||
mojira
|
||||
mothra
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -305,7 +310,7 @@ EOF
|
||||
|
||||
RUNS $jira done $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
@@ -336,7 +341,7 @@ EOF
|
||||
|
||||
RUNS $jira comment $issue --noedit -m "Yo, Comment"
|
||||
DIFF <<EOF
|
||||
OK $issue http://localhost:8080/browse/$issue
|
||||
OK $issue $ENDPOINT/browse/$issue
|
||||
EOF
|
||||
|
||||
RUNS $jira $issue
|
||||
@@ -357,7 +362,7 @@ description: |
|
||||
description
|
||||
|
||||
comments:
|
||||
- | # mojira, a minute ago
|
||||
- | # mothra, a minute ago
|
||||
Yo, Comment
|
||||
|
||||
EOF
|
||||
@@ -368,7 +373,7 @@ EOF
|
||||
|
||||
RUNS $jira add labels $blocker test-label another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -396,7 +401,7 @@ EOF
|
||||
|
||||
RUNS $jira remove labels $blocker another-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -424,7 +429,7 @@ EOF
|
||||
|
||||
RUNS $jira set labels $blocker more-label better-label
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -447,12 +452,12 @@ description: |
|
||||
EOF
|
||||
|
||||
###############################################################################
|
||||
## Verify that "mojira" user can take the issue (reassign to self)
|
||||
## Verify that "mothra" user can take the issue (reassign to self)
|
||||
###############################################################################
|
||||
|
||||
RUNS $jira take $blocker
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
@@ -463,7 +468,7 @@ status: Done
|
||||
summary: blocks
|
||||
project: TASK
|
||||
issuetype: Task
|
||||
assignee: mojira
|
||||
assignee: mothra
|
||||
reporter: gojira
|
||||
blockers:
|
||||
depends: $issue[To Do]
|
||||
@@ -480,7 +485,7 @@ EOF
|
||||
|
||||
RUNS $jira give $blocker gojira
|
||||
DIFF <<EOF
|
||||
OK $blocker http://localhost:8080/browse/$blocker
|
||||
OK $blocker $ENDPOINT/browse/$blocker
|
||||
EOF
|
||||
|
||||
RUNS $jira $blocker
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
FROM alpine:latest
|
||||
RUN apk --update add openjdk8-jre curl screen && \
|
||||
curl -s -L https://marketplace.atlassian.com/download/plugins/atlassian-plugin-sdk-tgz | tar xzf - && \
|
||||
ln -s /atlassian* /atlassian
|
||||
|
||||
ENV PATH=/bin:/usr/bin:/atlassian/bin
|
||||
|
||||
# Copy in the serivce and also the root .m2 settings to force cache everything.
|
||||
# We also copy in /root/.java settings to prevent the dumb spam prompt from
|
||||
# the atlas-run command:
|
||||
# Would you like to subscribe to the Atlassian developer mailing list? (Y/y/N/n) Y: :
|
||||
COPY dockerroot /
|
||||
WORKDIR /jiratestservice
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
# we wrap the command with screen so that the dumb atlas-run has a tty to watch. Without screen
|
||||
# there is no tty so atlas-run will immediately read an EOF (aka CTRL-D) and interpret that to
|
||||
# mean we want the service to begin the "graceful shutdown" and exit
|
||||
CMD ["screen", "-DmL", "atlas-run", "--http-port", "8080", "--context-path", "ROOT", "--server", "localhost"]
|
||||
@@ -1,3 +0,0 @@
|
||||
RUN curl -Ls https://raw.githubusercontent.com/cptactionhank/docker-atlassian-jira-software/master/docker-entrypoint.sh -o /docker-entrypoint.sh \
|
||||
&& chmod 755 /docker-entrypoint.sh \
|
||||
&& echo jira.websudo.is.disabled = true >> /var/atlassian/jira/jira-config.properties
|
||||
@@ -1,3 +0,0 @@
|
||||
INCLUDE MERGE -VOLUME -COPY \
|
||||
https://raw.githubusercontent.com/cptactionhank/docker-atlassian-jira-software/master/Dockerfile \
|
||||
Dockerfile.inc
|
||||
+16
-33
@@ -2,39 +2,6 @@
|
||||
|
||||
The test are written using the `osht` bash testing framework. Please read the [documentation](https://github.com/coryb/osht/blob/master/README.md) for `osht`.
|
||||
|
||||
## Setup
|
||||
These tests assume there is a jira service running at 127.0.0.1:8080 with user "gojira" and password "gojira123".
|
||||
There should also be a poweruser "admin" with password "admin123"
|
||||
|
||||
The test Jira was setup following the instructions [here](https://github.com/cptactionhank/docker-atlassian-jira).
|
||||
|
||||
|
||||
### build base docker image
|
||||
```
|
||||
docker run --rm -i -v $(pwd):/root:ro coryb/dfpp:1.0.2 Dockerfile.pre | docker build -t go-jira-base:latest -
|
||||
```
|
||||
|
||||
### Initialize container
|
||||
```
|
||||
docker run --detach --name go-jira-test --publish 8080:8080 go-jira-base:latest
|
||||
```
|
||||
|
||||
### create admin user
|
||||
```
|
||||
open http://localhost:8080
|
||||
```
|
||||
Then follow UI workflow to create "admin" user, skip intro and project creation.
|
||||
|
||||
### snapshot docker container
|
||||
```
|
||||
docker commit go-jira-test go-jira-test:latest
|
||||
```
|
||||
|
||||
### Destroy base container
|
||||
```
|
||||
docker rm -f go-jira-test
|
||||
```
|
||||
|
||||
## Running Test:
|
||||
|
||||
From the top level of the project you can run:
|
||||
@@ -46,8 +13,24 @@ make
|
||||
prove
|
||||
```
|
||||
|
||||
### Running individual tests
|
||||
To run a specific test you can run it directly like:
|
||||
```
|
||||
./100basic.t
|
||||
```
|
||||
There is a useful `-v` option to make the test more verbose and an `-a` option to casue the test to abort after the first failure.
|
||||
|
||||
The tests all require the jira service to be running from the docker container, so you will have to manually run the setup script:
|
||||
```
|
||||
./000setup.t
|
||||
```
|
||||
|
||||
After than you can run the other tests over and over. The jira service is just a test instance started for local development. It comes with
|
||||
a temporary license (I think it is 8 hours) so you will have to run the `./000setup.t` script at least once daily.
|
||||
|
||||
## API Documentation:
|
||||
https://docs.atlassian.com/jira/REST/cloud/
|
||||
https://docs.atlassian.com/jira-software/REST/cloud
|
||||
|
||||
## projectTempalteKey missing documentation
|
||||
https://answers.atlassian.com/questions/36176301/jira-api-7.1.0-create-project
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
To avoid future confusion, we recommend that you include a license with your plugin.
|
||||
This file is simply a reminder.
|
||||
|
||||
For a template license you can have a look at: http://www.opensource.org/licenses/
|
||||
|
||||
Atlassian releases most of its modules under the Apache2 license: http://opensource.org/licenses/Apache-2.0
|
||||
@@ -0,0 +1,13 @@
|
||||
You have successfully created an Atlassian Plugin!
|
||||
|
||||
Here are the SDK commands you'll use immediately:
|
||||
|
||||
* atlas-run -- installs this plugin into the product and starts it on localhost
|
||||
* atlas-debug -- same as atlas-run, but allows a debugger to attach at port 5005
|
||||
* atlas-cli -- after atlas-run or atlas-debug, opens a Maven command line window:
|
||||
- 'pi' reinstalls the plugin into the running product instance
|
||||
* atlas-help -- prints description for all commands in the SDK
|
||||
|
||||
Full documentation is always available at:
|
||||
|
||||
https://developer.atlassian.com/display/DOCS/Introduction+to+the+Atlassian+Plugin+SDK
|
||||
@@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.netflixskunkworks</groupId>
|
||||
<artifactId>jiratestservice</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<organization>
|
||||
<name>Example Company</name>
|
||||
<url>http://www.example.com/</url>
|
||||
</organization>
|
||||
|
||||
<name>jiratestservice</name>
|
||||
<description>This is the com.netflixskunkworks:jiratestservice plugin for Atlassian JIRA.</description>
|
||||
<packaging>atlassian-plugin</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.atlassian.jira</groupId>
|
||||
<artifactId>jira-api</artifactId>
|
||||
<version>${jira.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Add dependency on jira-core if you want access to JIRA implementation classes as well as the sanctioned API. -->
|
||||
<!-- This is not normally recommended, but may be required eg when migrating a plugin originally developed against JIRA 4.x -->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.atlassian.jira</groupId>
|
||||
<artifactId>jira-core</artifactId>
|
||||
<version>${jira.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.atlassian.plugin</groupId>
|
||||
<artifactId>atlassian-spring-scanner-annotation</artifactId>
|
||||
<version>${atlassian.spring.scanner.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.atlassian.plugin</groupId>
|
||||
<artifactId>atlassian-spring-scanner-runtime</artifactId>
|
||||
<version>${atlassian.spring.scanner.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<version>1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- WIRED TEST RUNNER DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>com.atlassian.plugins</groupId>
|
||||
<artifactId>atlassian-plugins-osgi-testrunner</artifactId>
|
||||
<version>${plugin.testrunner.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>jsr311-api</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.2.2-atlassian-1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
|
||||
<!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.atlassian.jira.tests</groupId>
|
||||
<artifactId>jira-testkit-client</artifactId>
|
||||
<version>${testkit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.atlassian.maven.plugins</groupId>
|
||||
<artifactId>maven-jira-plugin</artifactId>
|
||||
<version>${amps.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<applications>
|
||||
<application>
|
||||
<applicationKey>jira-software</applicationKey>
|
||||
<version>${jira.version}</version>
|
||||
</application>
|
||||
</applications>
|
||||
<productVersion>${jira.version}</productVersion>
|
||||
<productDataVersion>${jira.version}</productDataVersion>
|
||||
<!-- Uncomment to install TestKit backdoor in JIRA. -->
|
||||
<!--
|
||||
<pluginArtifacts>
|
||||
<pluginArtifact>
|
||||
<groupId>com.atlassian.jira.tests</groupId>
|
||||
<artifactId>jira-testkit-plugin</artifactId>
|
||||
<version>${testkit.version}</version>
|
||||
</pluginArtifact>
|
||||
</pluginArtifacts>
|
||||
-->
|
||||
<enableQuickReload>true</enableQuickReload>
|
||||
<enableFastdev>false</enableFastdev>
|
||||
|
||||
<!-- See here for an explanation of default instructions: -->
|
||||
<!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
|
||||
<instructions>
|
||||
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
|
||||
|
||||
<!-- Add package to export here -->
|
||||
<Export-Package>
|
||||
com.netflixskunkworks.api,
|
||||
</Export-Package>
|
||||
|
||||
<!-- Add package import here -->
|
||||
<Import-Package>
|
||||
org.springframework.osgi.*;resolution:="optional",
|
||||
org.eclipse.gemini.blueprint.*;resolution:="optional",
|
||||
*
|
||||
</Import-Package>
|
||||
|
||||
<!-- Ensure plugin is spring powered -->
|
||||
<Spring-Context>*</Spring-Context>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.atlassian.plugin</groupId>
|
||||
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
|
||||
<version>${atlassian.spring.scanner.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>atlassian-spring-scanner</goal>
|
||||
</goals>
|
||||
<phase>process-classes</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<scannedDependencies>
|
||||
<dependency>
|
||||
<groupId>com.atlassian.plugin</groupId>
|
||||
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
|
||||
</dependency>
|
||||
</scannedDependencies>
|
||||
<verbose>false</verbose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<jira.version>7.2.0</jira.version>
|
||||
<amps.version>6.2.6</amps.version>
|
||||
<plugin.testrunner.version>1.2.3</plugin.testrunner.version>
|
||||
<atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
|
||||
<!-- This key is used to keep the consistency between the key in atlassian-plugin.xml and the key to generate bundle. -->
|
||||
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
|
||||
<!-- TestKit version 6.x for JIRA 6.x -->
|
||||
<testkit.version>6.3.11</testkit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
|
||||
<plugin-info>
|
||||
<description>${project.description}</description>
|
||||
<version>${project.version}</version>
|
||||
<vendor name="${project.organization.name}" url="${project.organization.url}" />
|
||||
</plugin-info>
|
||||
</atlassian-plugin>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">
|
||||
<map MAP_XML_VERSION="1.0">
|
||||
<entry key="sdk-email-subscribe" value="true"/>
|
||||
</map>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">
|
||||
<map MAP_XML_VERSION="1.0">
|
||||
<entry key="last_update_check" value="2016-08-29"/>
|
||||
<entry key="sdk-pom-update-check-6.2.6-cbc3c672c37f65828d50132ed303cf7a" value="true"/>
|
||||
</map>
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||
<profiles>
|
||||
<!-- Default profile containing Atlassian servers -->
|
||||
<profile>
|
||||
<id>defaultProfile</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>atlassian-public</id>
|
||||
<url>https://maven.atlassian.com/repository/public</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>atlassian-plugin-sdk</id>
|
||||
<url>file://${env.ATLAS_HOME}/repository</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>atlassian-public</id>
|
||||
<url>https://maven.atlassian.com/repository/public</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>atlassian-plugin-sdk</id>
|
||||
<url>file://${env.ATLAS_HOME}/repository</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<properties>
|
||||
<downloadSources>true</downloadSources>
|
||||
<downloadJavadocs>true</downloadJavadocs>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</settings>
|
||||
+128
-60
@@ -1,60 +1,87 @@
|
||||
package jira
|
||||
|
||||
var all_templates = map[string]string{
|
||||
"debug": default_debug_template,
|
||||
"fields": default_debug_template,
|
||||
"editmeta": default_debug_template,
|
||||
"transmeta": default_debug_template,
|
||||
"createmeta": default_debug_template,
|
||||
"issuelinktypes": default_debug_template,
|
||||
"list": default_list_template,
|
||||
"table": default_table_template,
|
||||
"view": default_view_template,
|
||||
"edit": default_edit_template,
|
||||
"transitions": default_transitions_template,
|
||||
"components": default_components_template,
|
||||
"issuetypes": default_issuetypes_template,
|
||||
"create": default_create_template,
|
||||
"comment": default_comment_template,
|
||||
"transition": default_transition_template,
|
||||
"request": default_debug_template,
|
||||
var allTemplates = map[string]string{
|
||||
"debug": defaultDebugTemplate,
|
||||
"fields": defaultDebugTemplate,
|
||||
"editmeta": defaultDebugTemplate,
|
||||
"transmeta": defaultDebugTemplate,
|
||||
"createmeta": defaultDebugTemplate,
|
||||
"issuelinktypes": defaultDebugTemplate,
|
||||
"list": defaultListTemplate,
|
||||
"table": defaultTableTemplate,
|
||||
"view": defaultViewTemplate,
|
||||
"edit": defaultEditTemplate,
|
||||
"transitions": defaultTransitionsTemplate,
|
||||
"components": defaultComponentsTemplate,
|
||||
"issuetypes": defaultIssuetypesTemplate,
|
||||
"create": defaultCreateTemplate,
|
||||
"comment": defaultCommentTemplate,
|
||||
"transition": defaultTransitionTemplate,
|
||||
"request": defaultDebugTemplate,
|
||||
"worklog": defaultWorklogTemplate,
|
||||
"worklogs": defaultWorklogsTemplate,
|
||||
}
|
||||
|
||||
const default_debug_template = "{{ . | toJson}}\n"
|
||||
const defaultDebugTemplate = "{{ . | toJson}}\n"
|
||||
|
||||
const default_list_template = "{{ range .issues }}{{ .key | append \":\" | printf \"%-12s\"}} {{ .fields.summary }}\n{{ end }}"
|
||||
const defaultListTemplate = "{{ range .issues }}{{ .key | append \":\" | printf \"%-12s\"}} {{ .fields.summary }}\n{{ end }}"
|
||||
|
||||
const default_table_template = `+{{ "-" | rep 16 }}+{{ "-" | rep 57 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||
const defaultTableTemplate = `+{{ "-" | rep 16 }}+{{ "-" | rep 57 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||
| {{ "Issue" | printf "%-14s" }} | {{ "Summary" | printf "%-55s" }} | {{ "Priority" | printf "%-12s" }} | {{ "Status" | printf "%-12s" }} | {{ "Age" | printf "%-10s" }} | {{ "Reporter" | printf "%-12s" }} | {{ "Assignee" | printf "%-12s" }} |
|
||||
+{{ "-" | rep 16 }}+{{ "-" | rep 57 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||
{{ range .issues }}| {{ .key | printf "%-14s"}} | {{ .fields.summary | abbrev 55 | printf "%-55s" }} | {{.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 }}+{{ "-" | rep 16 }}+{{ "-" | rep 57 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||
{{ range .issues -}}
|
||||
| {{ .key | printf "%-14s"}} | {{ .fields.summary | abbrev 55 | printf "%-55s" }} | {{.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 -}}
|
||||
+{{ "-" | rep 16 }}+{{ "-" | rep 57 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+{{ "-" | rep 12 }}+{{ "-" | rep 14 }}+{{ "-" | rep 14 }}+
|
||||
`
|
||||
|
||||
const default_view_template = `issue: {{ .key }}{{if .fields.created}}
|
||||
created: {{ .fields.created | age }} ago{{end}}{{if .fields.status}}
|
||||
status: {{ .fields.status.name }}{{end}}
|
||||
const defaultViewTemplate = `{{/* view template */ -}}
|
||||
issue: {{ .key }}
|
||||
{{if .fields.created -}}
|
||||
created: {{ .fields.created | age }} ago
|
||||
{{end -}}
|
||||
{{if .fields.status -}}
|
||||
status: {{ .fields.status.name }}
|
||||
{{end -}}
|
||||
summary: {{ .fields.summary }}
|
||||
project: {{ .fields.project.key }}{{if .fields.components}}
|
||||
components: {{ range .fields.components }}{{ .name }} {{end}}{{end}}{{if .fields.issuetype}}
|
||||
issuetype: {{ .fields.issuetype.name }}{{end}}{{if .fields.assignee}}
|
||||
assignee: {{ .fields.assignee.name }}{{end}}
|
||||
reporter: {{ if .fields.reporter }}{{ .fields.reporter.name }}{{end}}{{if .fields.customfield_10110}}
|
||||
watchers: {{ range .fields.customfield_10110 }}{{ .name }} {{end}}{{end}}{{if .fields.issuelinks}}
|
||||
project: {{ .fields.project.key }}
|
||||
{{if .fields.components -}}
|
||||
components: {{ range .fields.components }}{{ .name }} {{end}}
|
||||
{{end -}}
|
||||
{{if .fields.issuetype -}}
|
||||
issuetype: {{ .fields.issuetype.name }}
|
||||
{{end -}}
|
||||
{{if .fields.assignee -}}
|
||||
assignee: {{ .fields.assignee.name }}
|
||||
{{end -}}
|
||||
reporter: {{ if .fields.reporter }}{{ .fields.reporter.name }}{{end}}
|
||||
{{if .fields.customfield_10110 -}}
|
||||
watchers: {{ range .fields.customfield_10110 }}{{ .name }} {{end}}
|
||||
{{end -}}
|
||||
{{if .fields.issuelinks -}}
|
||||
blockers: {{ range .fields.issuelinks }}{{if .outwardIssue}}{{ .outwardIssue.key }}[{{.outwardIssue.fields.status.name}}]{{end}}{{end}}
|
||||
depends: {{ range .fields.issuelinks }}{{if .inwardIssue}}{{ .inwardIssue.key }}[{{.inwardIssue.fields.status.name}}]{{end}}{{end}}{{end}}{{if .fields.priority}}
|
||||
priority: {{ .fields.priority.name }}{{end}}{{if .fields.votes}}
|
||||
votes: {{ .fields.votes.votes}}{{end}}{{if .fields.labels}}
|
||||
labels: {{ join ", " .fields.labels }}{{end}}
|
||||
depends: {{ range .fields.issuelinks }}{{if .inwardIssue}}{{ .inwardIssue.key }}[{{.inwardIssue.fields.status.name}}]{{end}}{{end}}
|
||||
{{end -}}
|
||||
{{if .fields.priority -}}
|
||||
priority: {{ .fields.priority.name }}
|
||||
{{end -}}
|
||||
{{if .fields.votes -}}
|
||||
votes: {{ .fields.votes.votes}}
|
||||
{{end -}}
|
||||
{{if .fields.labels -}}
|
||||
labels: {{ join ", " .fields.labels }}
|
||||
{{end -}}
|
||||
description: |
|
||||
{{ or .fields.description "" | indent 2 }}{{if .fields.comment.comments}}
|
||||
|
||||
{{ or .fields.description "" | indent 2 }}
|
||||
{{if .fields.comment.comments}}
|
||||
comments:
|
||||
{{ range .fields.comment.comments }} - | # {{.author.name}}, {{.created | age}} ago
|
||||
{{ or .body "" | indent 4}}
|
||||
{{end}}{{end}}
|
||||
{{end}}
|
||||
{{end -}}
|
||||
`
|
||||
const default_edit_template = `# issue: {{ .key }}
|
||||
const defaultEditTemplate = `{{/* edit template */ -}}
|
||||
# issue: {{ .key }}
|
||||
update:
|
||||
comment:
|
||||
- add:
|
||||
@@ -67,8 +94,8 @@ fields:
|
||||
- name: {{ .name }}{{end}}{{end}}
|
||||
assignee:
|
||||
name: {{ if .overrides.assignee }}{{.overrides.assignee}}{{else}}{{if .fields.assignee }}{{ .fields.assignee.name }}{{end}}{{end}}
|
||||
# reporter:
|
||||
# name: {{ if .overrides.reporter }}{{ .overrides.reporter }}{{else if .fields.reporter}}{{ .fields.reporter.name }}{{end}}
|
||||
reporter:
|
||||
name: {{ if .overrides.reporter }}{{ .overrides.reporter }}{{else if .fields.reporter}}{{ .fields.reporter.name }}{{end}}
|
||||
# watchers
|
||||
customfield_10110: {{ range .fields.customfield_10110 }}
|
||||
- name: {{ .name }}{{end}}{{if .overrides.watcher}}
|
||||
@@ -82,16 +109,17 @@ fields:
|
||||
# {{ or .body "" | indent 4 | comment}}
|
||||
# {{end}}
|
||||
`
|
||||
const default_transitions_template = `{{ range .transitions }}{{.id }}: {{.name}}
|
||||
const defaultTransitionsTemplate = `{{ range .transitions }}{{.id }}: {{.name}}
|
||||
{{end}}`
|
||||
|
||||
const default_components_template = `{{ range . }}{{.id }}: {{.name}}
|
||||
const defaultComponentsTemplate = `{{ range . }}{{.id }}: {{.name}}
|
||||
{{end}}`
|
||||
|
||||
const default_issuetypes_template = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}}
|
||||
const defaultIssuetypesTemplate = `{{ range .projects }}{{ range .issuetypes }}{{color "+bh"}}{{.name | append ":" | printf "%-13s" }}{{color "reset"}} {{.description}}
|
||||
{{end}}{{end}}`
|
||||
|
||||
const default_create_template = `fields:
|
||||
const defaultCreateTemplate = `{{/* create template */ -}}
|
||||
fields:
|
||||
project:
|
||||
key: {{ or .overrides.project "" }}
|
||||
issuetype:
|
||||
@@ -112,41 +140,81 @@ const default_create_template = `fields:
|
||||
- name: {{.}}{{end}}
|
||||
- name:{{end}}`
|
||||
|
||||
const default_comment_template = `body: |~
|
||||
const defaultCommentTemplate = `body: |~
|
||||
{{ or .overrides.comment "" | indent 2 }}
|
||||
`
|
||||
|
||||
const default_transition_template = `update:
|
||||
const defaultTransitionTemplate = `{{/* transition template */ -}}
|
||||
update:
|
||||
comment:
|
||||
- add:
|
||||
body: |~
|
||||
{{ or .overrides.comment "" | indent 10 }}
|
||||
fields:{{if .meta.fields.assignee}}
|
||||
fields:
|
||||
{{- if .meta.fields.assignee}}
|
||||
assignee:
|
||||
name: {{if .overrides.assignee}}{{.overrides.assignee}}{{else}}{{if .fields.assignee}}{{.fields.assignee.name}}{{end}}{{end}}{{end}}{{if .meta.fields.components}}
|
||||
name: {{if .overrides.assignee}}{{.overrides.assignee}}{{else}}{{if .fields.assignee}}{{.fields.assignee.name}}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.components}}
|
||||
components: # Values: {{ range .meta.fields.components.allowedValues }}{{.name}}, {{end}}{{if .overrides.components }}{{ range (split "," .overrides.components)}}
|
||||
- name: {{.}}{{end}}{{else}}{{ range .fields.components }}
|
||||
- name: {{ .name }}{{end}}{{end}}{{end}}{{if .meta.fields.description}}
|
||||
description: {{or .overrides.description .fields.description }}{{end}}{{if .meta.fields.fixVersions}}{{if .meta.fields.fixVersions.allowedValues}}
|
||||
- name: {{ .name }}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.description}}
|
||||
description: {{or .overrides.description .fields.description }}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.fixVersions -}}
|
||||
{{if .meta.fields.fixVersions.allowedValues}}
|
||||
fixVersions: # Values: {{ range .meta.fields.fixVersions.allowedValues }}{{.name}}, {{end}}{{if .overrides.fixVersions}}{{ range (split "," .overrides.fixVersions)}}
|
||||
- name: {{.}}{{end}}{{else}}{{range .fields.fixVersions}}
|
||||
- name: {{.}}{{end}}{{end}}{{end}}{{end}}{{if .meta.fields.issuetype}}
|
||||
- name: {{.}}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.issuetype}}
|
||||
issuetype: # Values: {{ range .meta.fields.issuetype.allowedValues }}{{.name}}, {{end}}
|
||||
name: {{if .overrides.issuetype}}{{.overrides.issuetype}}{{else}}{{if .fields.issuetype}}{{.fields.issuetype.name}}{{end}}{{end}}{{end}}{{if .meta.fields.labels}}
|
||||
name: {{if .overrides.issuetype}}{{.overrides.issuetype}}{{else}}{{if .fields.issuetype}}{{.fields.issuetype.name}}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.labels}}
|
||||
labels: {{range .fields.labels}}
|
||||
- {{.}}{{end}}{{if .overrides.labels}}{{range (split "," .overrides.labels)}}
|
||||
- {{.}}{{end}}{{end}}{{end}}{{if .meta.fields.priority}}
|
||||
- {{.}}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.priority}}
|
||||
priority: # Values: {{ range .meta.fields.priority.allowedValues }}{{.name}}, {{end}}
|
||||
name: {{ or .overrides.priority "unassigned" }}{{end}}{{if .meta.fields.reporter}}
|
||||
name: {{ or .overrides.priority "unassigned" }}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.reporter}}
|
||||
reporter:
|
||||
name: {{if .overrides.reporter}}{{.overrides.reporter}}{{else}}{{if .fields.reporter}}{{.fields.reporter.name}}{{end}}{{end}}{{end}}{{if .meta.fields.resolution}}
|
||||
name: {{if .overrides.reporter}}{{.overrides.reporter}}{{else}}{{if .fields.reporter}}{{.fields.reporter.name}}{{end}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.resolution}}
|
||||
resolution: # Values: {{ range .meta.fields.resolution.allowedValues }}{{.name}}, {{end}}
|
||||
name: {{if .overrides.resolution}}{{.overrides.resolution}}{{else if .fields.resolution}}{{.fields.resolution.name}}{{else}}{{or .overrides.defaultResolution "Fixed"}}{{end}}{{end}}{{if .meta.fields.summary}}
|
||||
summary: {{or .overrides.summary .fields.summary}}{{end}}{{if .meta.fields.versions.allowedValues}}
|
||||
name: {{if .overrides.resolution}}{{.overrides.resolution}}{{else if .fields.resolution}}{{.fields.resolution.name}}{{else}}{{or .overrides.defaultResolution "Fixed"}}{{end}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.summary}}
|
||||
summary: {{or .overrides.summary .fields.summary}}
|
||||
{{- end -}}
|
||||
{{if .meta.fields.versions.allowedValues}}
|
||||
versions: # Values: {{ range .meta.fields.versions.allowedValues }}{{.name}}, {{end}}{{if .overrides.versions}}{{ range (split "," .overrides.versions)}}
|
||||
- name: {{.}}{{end}}{{else}}{{range .fields.versions}}
|
||||
- name: {{.}}{{end}}{{end}}{{end}}
|
||||
- name: {{.}}{{end}}{{end}}
|
||||
{{- end}}
|
||||
transition:
|
||||
id: {{ .transition.id }}
|
||||
name: {{ .transition.name }}
|
||||
`
|
||||
|
||||
const defaultWorklogTemplate = `{{/* worklog template */ -}}
|
||||
# issue: {{ .issue }}
|
||||
comment: |~
|
||||
{{ or .comment "" }}
|
||||
timeSpent: {{ or .timeSpent "" }}
|
||||
started:
|
||||
`
|
||||
|
||||
const defaultWorklogsTemplate = `{{/* worklogs template */ -}}
|
||||
{{ range .worklogs }}- # {{.author.name}}, {{.created | age}} ago
|
||||
comment: {{ or .comment "" }}
|
||||
timeSpent: {{ .timeSpent }}
|
||||
|
||||
{{end}}`
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package jira
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Transport struct {
|
||||
shadow http.Transport
|
||||
}
|
||||
|
||||
func NewUnixProxyTransport(path string) *Transport {
|
||||
dial := func(network, addr string) (net.Conn, error) {
|
||||
return net.Dial("unix", path)
|
||||
}
|
||||
|
||||
shadow := http.Transport{
|
||||
Dial: dial,
|
||||
DialTLS: dial,
|
||||
DisableKeepAlives: true,
|
||||
ResponseHeaderTimeout: 30 * time.Second,
|
||||
ExpectContinueTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
return &Transport{shadow}
|
||||
}
|
||||
|
||||
func UnixProxy(path string) *Transport {
|
||||
return NewUnixProxyTransport(os.ExpandEnv(path))
|
||||
}
|
||||
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req2 := *req
|
||||
url2 := *req.URL
|
||||
req2.URL = &url2
|
||||
req2.URL.Opaque = fmt.Sprintf("//%s%s", req.URL.Host, req.URL.EscapedPath())
|
||||
return t.shadow.RoundTrip(&req2)
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mgutz/ansi"
|
||||
"gopkg.in/coryb/yaml.v2"
|
||||
@@ -26,10 +25,12 @@ func homedir() string {
|
||||
return os.Getenv("HOME")
|
||||
}
|
||||
|
||||
// FindParentPaths will find all available paths from the current path up to the root
|
||||
// that matches the given fileName path
|
||||
func FindParentPaths(fileName string) []string {
|
||||
cwd, _ := os.Getwd()
|
||||
|
||||
paths := make([]string, 0)
|
||||
paths := []string{}
|
||||
|
||||
// special case if homedir is not in current path then check there anyway
|
||||
homedir := homedir()
|
||||
@@ -57,12 +58,14 @@ func FindParentPaths(fileName string) []string {
|
||||
return paths
|
||||
}
|
||||
|
||||
// FindClosestParentPath finds the path that matches the given fileName path that is
|
||||
// closest to the current working directory
|
||||
func FindClosestParentPath(fileName string) (string, error) {
|
||||
paths := FindParentPaths(fileName)
|
||||
if len(paths) > 0 {
|
||||
return paths[len(paths)-1], nil
|
||||
}
|
||||
return "", errors.New(fmt.Sprintf("%s not found in parent directory hierarchy", fileName))
|
||||
return "", fmt.Errorf("%s not found in parent directory hierarchy", fileName)
|
||||
}
|
||||
|
||||
func readFile(file string) string {
|
||||
@@ -92,35 +95,36 @@ func copyFile(src, dst string) (err error) {
|
||||
}
|
||||
|
||||
func fuzzyAge(start string) (string, error) {
|
||||
if t, err := time.Parse("2006-01-02T15:04:05.000-0700", start); err != nil {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.000-0700", start)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
delta := time.Now().Sub(t)
|
||||
if delta.Minutes() < 2 {
|
||||
return "a minute", nil
|
||||
} else if dm := delta.Minutes(); dm < 45 {
|
||||
return fmt.Sprintf("%d minutes", int(dm)), nil
|
||||
} else if dm := delta.Minutes(); dm < 90 {
|
||||
return "an hour", nil
|
||||
} else if dh := delta.Hours(); dh < 24 {
|
||||
return fmt.Sprintf("%d hours", int(dh)), nil
|
||||
} else if dh := delta.Hours(); dh < 48 {
|
||||
return "a day", nil
|
||||
} else {
|
||||
return fmt.Sprintf("%d days", int(delta.Hours()/24)), nil
|
||||
}
|
||||
}
|
||||
return "unknown", nil
|
||||
delta := time.Now().Sub(t)
|
||||
if delta.Minutes() < 2 {
|
||||
return "a minute", nil
|
||||
} else if dm := delta.Minutes(); dm < 45 {
|
||||
return fmt.Sprintf("%d minutes", int(dm)), nil
|
||||
} else if dm := delta.Minutes(); dm < 90 {
|
||||
return "an hour", nil
|
||||
} else if dh := delta.Hours(); dh < 24 {
|
||||
return fmt.Sprintf("%d hours", int(dh)), nil
|
||||
} else if dh := delta.Hours(); dh < 48 {
|
||||
return "a day", nil
|
||||
}
|
||||
return fmt.Sprintf("%d days", int(delta.Hours()/24)), nil
|
||||
}
|
||||
|
||||
func dateFormat(format string, content string) (string, error) {
|
||||
if t, err := time.Parse("2006-01-02T15:04:05.000-0700", content); err != nil {
|
||||
t, err := time.Parse("2006-01-02T15:04:05.000-0700", content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return t.Format(format), nil
|
||||
}
|
||||
return t.Format(format), nil
|
||||
}
|
||||
|
||||
// RunTemplate will run the give templateContent as a golang text/template
|
||||
// and pass the provided data to the template execution. It will write
|
||||
// the output to the provided "out" writer.
|
||||
func RunTemplate(templateContent string, data interface{}, out io.Writer) error {
|
||||
return runTemplate(templateContent, data, out)
|
||||
}
|
||||
@@ -132,11 +136,11 @@ func runTemplate(templateContent string, data interface{}, out io.Writer) error
|
||||
|
||||
funcs := map[string]interface{}{
|
||||
"toJson": func(content interface{}) (string, error) {
|
||||
if bytes, err := json.MarshalIndent(content, "", " "); err != nil {
|
||||
bytes, err := json.MarshalIndent(content, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return string(bytes), nil
|
||||
}
|
||||
return string(bytes), nil
|
||||
},
|
||||
"append": func(more string, content interface{}) (string, error) {
|
||||
switch value := content.(type) {
|
||||
@@ -145,13 +149,13 @@ func runTemplate(templateContent string, data interface{}, out io.Writer) error
|
||||
case []byte:
|
||||
return string(append(content.([]byte), []byte(more)...)), nil
|
||||
default:
|
||||
return "", errors.New(fmt.Sprintf("Unknown type: %s", value))
|
||||
return "", fmt.Errorf("Unknown type: %s", value)
|
||||
}
|
||||
},
|
||||
"indent": func(spaces int, content string) string {
|
||||
indent := make([]rune, spaces+1, spaces+1)
|
||||
indent[0] = '\n'
|
||||
for i := 1; i < spaces+1; i += 1 {
|
||||
for i := 1; i < spaces+1; i++ {
|
||||
indent[i] = ' '
|
||||
}
|
||||
|
||||
@@ -194,7 +198,7 @@ func runTemplate(templateContent string, data interface{}, out io.Writer) error
|
||||
},
|
||||
"rep": func(count int, content string) string {
|
||||
var buffer bytes.Buffer
|
||||
for i := 0; i < count; i += 1 {
|
||||
for i := 0; i < count; i++ {
|
||||
buffer.WriteString(content)
|
||||
}
|
||||
return buffer.String()
|
||||
@@ -206,19 +210,19 @@ func runTemplate(templateContent string, data interface{}, out io.Writer) error
|
||||
return dateFormat(format, content)
|
||||
},
|
||||
}
|
||||
if tmpl, err := template.New("template").Funcs(funcs).Parse(templateContent); err != nil {
|
||||
tmpl, err := template.New("template").Funcs(funcs).Parse(templateContent)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to parse template: %s", err)
|
||||
return err
|
||||
} else {
|
||||
if err := tmpl.Execute(out, data); err != nil {
|
||||
log.Errorf("Failed to execute template: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tmpl.Execute(out, data); err != nil {
|
||||
log.Errorf("Failed to execute template: %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func responseToJson(resp *http.Response, err error) (interface{}, error) {
|
||||
func responseToJSON(resp *http.Response, err error) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -367,7 +371,7 @@ func mkdir(dir string) error {
|
||||
log.Errorf("Failed to stat %s: %s", dir, err)
|
||||
return err
|
||||
} else if err == nil && !stat.IsDir() {
|
||||
err := fmt.Errorf("%s exists and is not a directory!", dir)
|
||||
err := fmt.Errorf("%s exists and is not a directory", dir)
|
||||
log.Errorf("%s", err)
|
||||
return err
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user