add basic tests for custom-commands

This commit is contained in:
Cory Bennett
2017-09-09 17:20:57 -07:00
parent 29b95a52cb
commit c585244f3e
8 changed files with 235 additions and 60 deletions
Generated
+4 -4
View File
@@ -1,5 +1,5 @@
hash: 4c3ae9c9421b17aae9987ea9566cac7d0a789750bb77c8d235b7be163aec8cae hash: 4c3ae9c9421b17aae9987ea9566cac7d0a789750bb77c8d235b7be163aec8cae
updated: 2017-09-08T18:47:08.390962401-07:00 updated: 2017-09-09T17:13:22.172913984-07:00
imports: imports:
- name: github.com/alecthomas/template - name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c version: a0175ee3bccc567396460bf5acd36800cb10c49c
@@ -12,7 +12,7 @@ imports:
subpackages: subpackages:
- generic - generic
- name: github.com/coryb/figtree - name: github.com/coryb/figtree
version: 4429db55820d818320f5af8971ef8401baaf3d21 version: 86e7c859d0326621c45ba7be2c32e3b3ae203213
- name: github.com/coryb/kingpeon - name: github.com/coryb/kingpeon
version: 64b561ae2d0f895b94719c486bed798f4236a4b3 version: 64b561ae2d0f895b94719c486bed798f4236a4b3
- name: github.com/coryb/oreo - name: github.com/coryb/oreo
@@ -42,11 +42,11 @@ imports:
- name: github.com/tmc/keyring - name: github.com/tmc/keyring
version: 06e6283d50adc5f8fcdb3cdf33ee1244d4400ae1 version: 06e6283d50adc5f8fcdb3cdf33ee1244d4400ae1
- name: golang.org/x/crypto - name: golang.org/x/crypto
version: 81e90905daefcd6fd217b62423c0908922eadb30 version: 9ba3862cf6a5452ae579de98f9364dd2e544844c
subpackages: subpackages:
- ssh/terminal - ssh/terminal
- name: golang.org/x/sys - name: golang.org/x/sys
version: 5513e650ab47a692d3a036d49be8fa52ddd09b65 version: a5054c7c1385fd50d9394475365355a87a7873ec
subpackages: subpackages:
- unix - unix
- windows - windows
+21
View File
@@ -3,3 +3,24 @@ config:
password-source: pass password-source: pass
endpoint: https://go-jira.atlassian.net endpoint: https://go-jira.atlassian.net
user: gojira user: gojira
project: BASIC
custom-commands:
- name: env
help: print the JIRA environment variables available to custom commands
script: |-
env | sort | grep JIRA
- name: print-project
help: print the name of the configured project
script: "echo $JIRA_PROJECT"
- name: mine
help: display issues assigned to me
script: |-
if [ -n "$JIRA_PROJECT" ]; then
# if `project: ...` configured just list the issues for current project
jira list --template table --query "resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created"
else
# otherwise list issues for all project
jira list --template table --query "resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created"
fi
+61
View File
@@ -0,0 +1,61 @@
#!/bin/bash
eval "$(curl -q -s https://raw.githubusercontent.com/coryb/osht/master/osht.sh)"
cd $(dirname $0)
jira="../jira"
. env.sh
PLAN 10
# reset login
RUNS $jira logout
RUNS $jira login
# cleanup from previous failed test executions
($jira ls --project BASIC | awk -F: '{print $1}' | while read issue; do ../jira done $issue; done) | sed 's/^/# CLEANUP: /g'
###############################################################################
## Create an issue
###############################################################################
RUNS $jira create --project BASIC -o summary=summary -o description=description --noedit --saveFile issue.props
issue=$(awk '/issue/{print $2}' issue.props)
DIFF <<EOF
OK $issue $ENDPOINT/browse/$issue
EOF
###############################################################################
## Testing the example custom commands, print-project
###############################################################################
RUNS $jira print-project
DIFF <<EOF
BASIC
EOF
###############################################################################
## Testing the example custom commands, env
###############################################################################
RUNS $jira env
DIFF <<'EOF'
JIRACLOUD=1
JIRA_CUSTOM_COMMANDS=[{"name":"env","script":"env | sort | grep JIRA","help":"print the JIRA environment variables available to custom commands"},{"name":"print-project","script":"echo $JIRA_PROJECT","help":"print the name of the configured project"},{"name":"mine","script":"if [ -n \"$JIRA_PROJECT\" ]; then\n # if `project: ...` configured just list the issues for current project\n jira list --template table --query \"resolution = unresolved and assignee=currentuser() and project = $JIRA_PROJECT ORDER BY priority asc, created\"\nelse\n # otherwise list issues for all project\n jira list --template table --query \"resolution = unresolved and assignee=currentuser() ORDER BY priority asc, created\"\nfi","help":"display issues assigned to me"}]
JIRA_ENDPOINT=https://go-jira.atlassian.net
JIRA_LOG_FORMAT=%{level:-5s} %{message}
JIRA_PASSWORD_SOURCE=pass
JIRA_PROJECT=BASIC
JIRA_USER=gojira
EOF
###############################################################################
## Use the "mine" alias to list issues assigned to self
###############################################################################
RUNS $jira mine
DIFF <<EOF
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
| Issue | Summary | Priority | Status | Age | Reporter | Assignee |
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
| $(printf %-14s $issue) | summary | Medium | To Do | a minute | gojira | gojira |
+----------------+---------------------------------------------------------+--------------+--------------+------------+--------------+--------------+
EOF
+64 -50
View File
@@ -104,11 +104,11 @@ func (f *FigTree) LoadConfigBytes(config []byte, source string, options interfac
reflect.ValueOf(options), reflect.ValueOf(options),
reflect.ValueOf(tmp), reflect.ValueOf(tmp),
) )
f.populateEnv(options)
if m.Config.Stop { if m.Config.Stop {
f.stop = true f.stop = true
return nil return nil
} }
f.populateEnv(options)
return nil return nil
} }
@@ -350,6 +350,60 @@ Outer:
return ov return ov
} }
func (f *FigTree) formatEnvName(name string) string {
name = fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))
return strings.Map(func(r rune) rune {
if unicode.IsDigit(r) || unicode.IsLetter(r) {
return r
}
return '_'
}, name)
}
func (f *FigTree) formatEnvValue(value reflect.Value) (string, bool) {
switch t := value.Interface().(type) {
case string:
return t, true
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
return fmt.Sprintf("%v", t), true
default:
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if value.IsNil() {
return "", false
}
}
if t == nil {
return "", false
}
type definable interface {
IsDefined() bool
}
if def, ok := t.(definable); ok {
// skip fields that are not defined
if !def.IsDefined() {
return "", false
}
}
type gettable interface {
GetValue() interface{}
}
if get, ok := t.(gettable); ok {
return fmt.Sprintf("%v", get.GetValue()), true
} else {
if b, err := json.Marshal(t); err == nil {
val := strings.TrimSpace(string(b))
if val == "null" {
return "", true
}
return val, true
}
}
}
return "", false
}
func (f *FigTree) populateEnv(data interface{}) { func (f *FigTree) populateEnv(data interface{}) {
options := reflect.ValueOf(data) options := reflect.ValueOf(data)
if options.Kind() == reflect.Ptr { if options.Kind() == reflect.Ptr {
@@ -370,8 +424,11 @@ func (f *FigTree) populateEnv(data interface{}) {
} }
name := strings.Join(allParts, "_") name := strings.Join(allParts, "_")
envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name)) envName := f.formatEnvName(name)
os.Setenv(envName, fmt.Sprintf("%v", options.MapIndex(key).Interface())) val, ok := f.formatEnvValue(options.MapIndex(key))
if ok {
os.Setenv(envName, val)
}
} }
} }
} else if options.Kind() == reflect.Struct { } else if options.Kind() == reflect.Struct {
@@ -400,54 +457,11 @@ func (f *FigTree) populateEnv(data interface{}) {
} }
} }
envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name)) envName := f.formatEnvName(name)
val, ok := f.formatEnvValue(options.Field(i))
envName = strings.Map(func(r rune) rune { if ok {
if unicode.IsDigit(r) || unicode.IsLetter(r) { os.Setenv(envName, val)
return r
}
return '_'
}, envName)
var val string
switch t := options.Field(i).Interface().(type) {
case string:
val = t
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
val = fmt.Sprintf("%v", t)
default:
switch options.Field(i).Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if options.Field(i).IsNil() {
continue
}
}
if t == nil {
continue
}
type definable interface {
IsDefined() bool
}
if def, ok := t.(definable); ok {
// skip fields that are not defined
if !def.IsDefined() {
continue
}
}
type gettable interface {
GetValue() interface{}
}
if get, ok := t.(gettable); ok {
val = fmt.Sprintf("%v", get.GetValue())
} else {
if b, err := json.Marshal(t); err == nil {
val = strings.TrimSpace(string(b))
if val == "null" {
val = ""
}
}
}
} }
os.Setenv(envName, val)
} }
} }
} }
+18 -1
View File
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/* /*
Package box authenticates and encrypts messages using public-key cryptography. Package box authenticates and encrypts small messages using public-key cryptography.
Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
messages. The length of messages is not hidden. messages. The length of messages is not hidden.
@@ -13,6 +13,23 @@ example, by using nonce 1 for the first message, nonce 2 for the second
message, etc. Nonces are long enough that randomly generated nonces have message, etc. Nonces are long enough that randomly generated nonces have
negligible risk of collision. negligible risk of collision.
Messages should be small because:
1. The whole message needs to be held in memory to be processed.
2. Using large messages pressures implementations on small machines to decrypt
and process plaintext before authenticating it. This is very dangerous, and
this API does not allow it, but a protocol that uses excessive message sizes
might present some implementations with no other choice.
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
4. Performance may be improved by working with messages that fit into data caches.
Thus large amounts of data should be chunked so that each message is small.
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html. This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
*/ */
package box // import "golang.org/x/crypto/nacl/box" package box // import "golang.org/x/crypto/nacl/box"
+17
View File
@@ -13,6 +13,23 @@ example, by using nonce 1 for the first message, nonce 2 for the second
message, etc. Nonces are long enough that randomly generated nonces have message, etc. Nonces are long enough that randomly generated nonces have
negligible risk of collision. negligible risk of collision.
Messages should be small because:
1. The whole message needs to be held in memory to be processed.
2. Using large messages pressures implementations on small machines to decrypt
and process plaintext before authenticating it. This is very dangerous, and
this API does not allow it, but a protocol that uses excessive message sizes
might present some implementations with no other choice.
3. Fixed overheads will be sufficiently amortised by messages as small as 8KB.
4. Performance may be improved by working with messages that fit into data caches.
Thus large amounts of data should be chunked so that each message is small.
(Each message still needs a unique nonce.) If in doubt, 16KB is a reasonable
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html. This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
*/ */
package secretbox // import "golang.org/x/crypto/nacl/secretbox" package secretbox // import "golang.org/x/crypto/nacl/secretbox"
+20 -5
View File
@@ -12,7 +12,10 @@ import (
) )
func TestKeyExpiry(t *testing.T) { func TestKeyExpiry(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(expiringKeyHex)) kring, err := ReadKeyRing(readerFromHex(expiringKeyHex))
if err != nil {
t.Fatal(err)
}
entity := kring[0] entity := kring[0]
const timeFormat = "2006-01-02" const timeFormat = "2006-01-02"
@@ -104,7 +107,10 @@ func TestGoodCrossSignature(t *testing.T) {
// TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission. // TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission.
func TestExternallyRevocableKey(t *testing.T) { func TestExternallyRevocableKey(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(subkeyUsageHex)) kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex))
if err != nil {
t.Fatal(err)
}
// The 0xA42704B92866382A key can be revoked by 0xBE3893CB843D0FE70C // The 0xA42704B92866382A key can be revoked by 0xBE3893CB843D0FE70C
// according to this signature that appears within the key: // according to this signature that appears within the key:
@@ -125,7 +131,10 @@ func TestExternallyRevocableKey(t *testing.T) {
} }
func TestKeyRevocation(t *testing.T) { func TestKeyRevocation(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(revokedKeyHex)) kring, err := ReadKeyRing(readerFromHex(revokedKeyHex))
if err != nil {
t.Fatal(err)
}
// revokedKeyHex contains these keys: // revokedKeyHex contains these keys:
// pub 1024R/9A34F7C0 2014-03-25 [revoked: 2014-03-25] // pub 1024R/9A34F7C0 2014-03-25 [revoked: 2014-03-25]
@@ -145,7 +154,10 @@ func TestKeyRevocation(t *testing.T) {
} }
func TestSubkeyRevocation(t *testing.T) { func TestSubkeyRevocation(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(revokedSubkeyHex)) kring, err := ReadKeyRing(readerFromHex(revokedSubkeyHex))
if err != nil {
t.Fatal(err)
}
// revokedSubkeyHex contains these keys: // revokedSubkeyHex contains these keys:
// pub 1024R/4EF7E4BECCDE97F0 2014-03-25 // pub 1024R/4EF7E4BECCDE97F0 2014-03-25
@@ -178,7 +190,10 @@ func TestSubkeyRevocation(t *testing.T) {
} }
func TestKeyUsage(t *testing.T) { func TestKeyUsage(t *testing.T) {
kring, _ := ReadKeyRing(readerFromHex(subkeyUsageHex)) kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex))
if err != nil {
t.Fatal(err)
}
// subkeyUsageHex contains these keys: // subkeyUsageHex contains these keys:
// pub 1024R/2866382A created: 2014-04-01 expires: never usage: SC // pub 1024R/2866382A created: 2014-04-01 expires: never usage: SC
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Functions to access/create device major and minor numbers matching the
// encoding used in FreeBSD's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a FreeBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a FreeBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a FreeBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return uint64((major << 8) | minor)
}