Browse Source

Merge pull request #46 from jmccann/secrets

Remove secrets
pull/54/head
Jacob McCann 7 years ago
committed by GitHub
parent
commit
4423c336c5
  1. 64
      DOCS.md
  2. 2
      Dockerfile
  3. 20
      plugin.go
  4. 23
      plugin_test.go
  5. 19
      vendor/github.com/franela/goblin/LICENSE
  6. 3
      vendor/github.com/franela/goblin/Makefile
  7. 141
      vendor/github.com/franela/goblin/README.md
  8. 59
      vendor/github.com/franela/goblin/assertions.go
  9. 36
      vendor/github.com/franela/goblin/go.snippets
  10. 302
      vendor/github.com/franela/goblin/goblin.go
  11. BIN
      vendor/github.com/franela/goblin/goblin_logo.jpg
  12. BIN
      vendor/github.com/franela/goblin/goblin_output.png
  13. 26
      vendor/github.com/franela/goblin/mono_reporter.go
  14. 137
      vendor/github.com/franela/goblin/reporting.go
  15. 21
      vendor/github.com/franela/goblin/resolver.go
  16. 8
      vendor/vendor.json

64
DOCS.md

@ -29,8 +29,11 @@ pipeline:
+ app_version: 1.0.0 + app_version: 1.0.0
``` ```
Example configuration passing secrets to terraform via `vars`. The following Example configuration passing secrets to terraform. Please read
example will call `terraform apply -var my_secret=${TERRAFORM_SECRET}`: https://www.terraform.io/docs/configuration/variables.html#environment-variables
for more details.
**Drone 0.6+**:
```diff ```diff
pipeline: pipeline:
@ -38,7 +41,26 @@ pipeline:
image: jmccann/drone-terraform:1 image: jmccann/drone-terraform:1
plan: false plan: false
+ secrets: + secrets:
+ my_secret: TERRAFORM_SECRET + - source: terraform_secret
+ target: tf_var_my_secret
```
**Drone 0.5**:
```diff
pipeline:
terraform_1:
image: jmccann/drone-terraform:1
plan: false
+ environment:
+ TF_VAR_MY_SECRET: ${TERRAFORM_SECRET}
terraform_2:
image: jmccann/drone-terraform:1
plan: false
+ sensitive: true
+ vars:
+ my_secret: ${TERRAFORM_SECRET}
``` ```
You may be passing sensitive vars to your terraform commands. If you do not want You may be passing sensitive vars to your terraform commands. If you do not want
@ -138,36 +160,6 @@ pipeline:
+ parallelism: 2 + parallelism: 2
``` ```
If you need to set different ENV secrets for multiple `terraform` steps you can utilize `secrets`.
The following example shows using different remotes secrets each step.
```yaml
pipeline:
dev_terraform:
image: jmccann/drone-terraform:1
plan: false
init_options:
backend_config:
- "bucket=my-terraform-config-bucket"
- "key=tf-states/my-project"
- "region=us-east-1"
+ secrets:
+ AWS_ACCESS_KEY_ID: DEV_AWS_ACCESS_KEY_ID
+ AWS_SECRET_ACCESS_KEY: DEV_AWS_SECRET_ACCESS_KEY
prod_terraform:
image: jmccann/drone-terraform:1
plan: false
init_options:
backend_config:
- "bucket=my-terraform-config-bucket"
- "key=tf-states/my-project"
- "region=us-east-1"
+ secrets:
+ AWS_ACCESS_KEY_ID: PROD_AWS_ACCESS_KEY_ID
+ AWS_SECRET_ACCESS_KEY: PROD_AWS_SECRET_ACCESS_KEY
```
Destroying the service can be done using the boolean `destory` option. Keep in mind that Fastly won't allow a service with active version be destoryed. Use `force_destroy` option in the service definition for terraform to handle it. Destroying the service can be done using the boolean `destory` option. Keep in mind that Fastly won't allow a service with active version be destoryed. Use `force_destroy` option in the service definition for terraform to handle it.
```yaml ```yaml
@ -205,12 +197,6 @@ var_files
: a list of variable files to pass to the Terraform `plan` and `apply` commands. : a list of variable files to pass to the Terraform `plan` and `apply` commands.
Each value is passed as a `-var-file <value>` option. Each value is passed as a `-var-file <value>` option.
secrets
: a map of variables to pass to the Terraform `plan` and `apply` commands as well as setting envvars.
The `key` is the var and ENV to set. The `value` is the ENV to read the value from.
* Each entry generate a terraform var as follows: `-var <key>=$<value>`
* Additionally each entry generate sets and envvar as follows: `key=$value`
ca_cert ca_cert
: ca cert to add to your environment to allow terraform to use internal/private resources : ca cert to add to your environment to allow terraform to use internal/private resources

2
Dockerfile

@ -1,6 +1,6 @@
# Docker image for the Drone Terraform plugin # Docker image for the Drone Terraform plugin
# #
# docker build --rm=true -t jmccann/drone-terraform:latest . # docker build -t jmccann/drone-terraform:latest .
FROM golang:1.8-alpine AS builder FROM golang:1.8-alpine AS builder
COPY ./*.go ./src/ COPY ./*.go ./src/
COPY ./vendor/ ./src/ COPY ./vendor/ ./src/

20
plugin.go

@ -5,6 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"regexp"
"strings" "strings"
"time" "time"
@ -53,9 +54,7 @@ func (p Plugin) Exec() error {
var commands []*exec.Cmd var commands []*exec.Cmd
if len(p.Config.Secrets) != 0 { CopyTfEnv()
exportSecrets(p.Config.Secrets)
}
if p.Config.Cacert != "" { if p.Config.Cacert != "" {
commands = append(commands, installCaCert(p.Config.Cacert)) commands = append(commands, installCaCert(p.Config.Cacert))
@ -108,9 +107,14 @@ func installCaCert(cacert string) *exec.Cmd {
) )
} }
func exportSecrets(secrets map[string]string) { func CopyTfEnv() {
for k, v := range secrets { tfVar := regexp.MustCompile(`^TF_VAR_.*$`)
os.Setenv(fmt.Sprintf("%s", k), fmt.Sprintf("%s", os.Getenv(v))) for _, e := range os.Environ() {
pair := strings.SplitN(e, "=", 2)
if tfVar.MatchString(pair[0]) {
name := strings.Split(pair[0], "TF_VAR_")
os.Setenv(fmt.Sprintf("TF_VAR_%s", strings.ToLower(name[1])), pair[1])
}
} }
} }
@ -187,10 +191,6 @@ func planCommand(config Config) *exec.Cmd {
args = append(args, "-var") args = append(args, "-var")
args = append(args, fmt.Sprintf("%s=%s", k, v)) args = append(args, fmt.Sprintf("%s=%s", k, v))
} }
for k, v := range config.Secrets {
args = append(args, "-var")
args = append(args, fmt.Sprintf("%s=%s", k, os.Getenv(v)))
}
if config.Parallelism > 0 { if config.Parallelism > 0 {
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism)) args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
} }

23
plugin_test.go

@ -1,9 +1,12 @@
package main package main
import ( import (
"os"
"os/exec" "os/exec"
"reflect" "reflect"
"testing" "testing"
. "github.com/franela/goblin"
) )
func Test_destroyCommand(t *testing.T) { func Test_destroyCommand(t *testing.T) {
@ -131,3 +134,23 @@ func Test_planCommand(t *testing.T) {
}) })
} }
} }
func TestPlugin(t *testing.T) {
g := Goblin(t)
g.Describe("CopyTfEnv", func() {
g.It("Should create copies of TF_VAR_ to lowercase", func() {
// Set some initial TF_VAR_ that are uppercase
os.Setenv("TF_VAR_SOMETHING", "some value")
os.Setenv("TF_VAR_SOMETHING_ELSE", "some other value")
os.Setenv("TF_VAR_BASE64", "dGVzdA==")
CopyTfEnv()
// Make sure new env vars exist with proper values
g.Assert(os.Getenv("TF_VAR_something")).Equal("some value")
g.Assert(os.Getenv("TF_VAR_something_else")).Equal("some other value")
g.Assert(os.Getenv("TF_VAR_base64")).Equal("dGVzdA==")
})
})
}

19
vendor/github.com/franela/goblin/LICENSE

@ -0,0 +1,19 @@
Copyright (c) 2013 Marcos Lilljedahl and Jonathan Leibiusky
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3
vendor/github.com/franela/goblin/Makefile

@ -0,0 +1,3 @@
export GOPATH=$(shell pwd)
test:
go test -v

141
vendor/github.com/franela/goblin/README.md

@ -0,0 +1,141 @@
[![Build Status](https://travis-ci.org/franela/goblin.png?branch=master)](https://travis-ci.org/franela/goblin)
Goblin
======
![](https://github.com/marcosnils/goblin/blob/master/goblin_logo.jpg?raw=true)
A [Mocha](http://mochajs.org/) like BDD testing framework for Go
No extensive documentation nor complicated steps to get it running
Run tests as usual with `go test`
Colorful reports and beautiful syntax
Why Goblin?
-----------
Inspired by the flexibility and simplicity of Node BDD and frustrated by the
rigorousness of Go way of testing, we wanted to bring a new tool to
write self-describing and comprehensive code.
What do I get with it?
----------------------
- Preserve the exact same syntax and behaviour as Node's Mocha
- Nest as many `Describe` and `It` blocks as you want
- Use `Before`, `BeforeEach`, `After` and `AfterEach` for setup and teardown your tests
- No need to remember confusing parameters in `Describe` and `It` blocks
- Use a declarative and expressive language to write your tests
- Plug different assertion libraries ([Gomega](https://github.com/onsi/gomega) supported so far)
- Skip your tests the same way as you would do in Mocha
- Automatic terminal support for colored outputs
- Two line setup is all you need to get up running
How do I use it?
----------------
Since ```go test``` is not currently extensive, you will have to hook Goblin to it. You do that by
adding a single test method in your test file. All your goblin tests will be implemented inside this function.
```go
package foobar
import (
"testing"
. "github.com/franela/goblin"
)
func Test(t *testing.T) {
g := Goblin(t)
g.Describe("Numbers", func() {
g.It("Should add two numbers ", func() {
g.Assert(1+1).Equal(2)
})
g.It("Should match equal numbers", func() {
g.Assert(2).Equal(4)
})
g.It("Should substract two numbers")
})
}
```
Ouput will be something like:
![](https://github.com/marcosnils/goblin/blob/master/goblin_output.png?raw=true)
Nice and easy, right?
Can I do asynchronous tests?
----------------------------
Yes! Goblin will help you to test asynchronous things, like goroutines, etc. You just need to add a ```done``` parameter to the handler function of your ```It```. This handler function should be called when your test passes.
```go
...
g.Describe("Numbers", func() {
g.It("Should add two numbers asynchronously", func(done Done) {
go func() {
g.Assert(1+1).Equal(2)
done()
}()
})
})
...
```
Goblin will wait for the ```done``` call, a ```Fail``` call or any false assertion.
How do I use it with Gomega?
----------------------------
Gomega is a nice assertion framework. But it doesn't provide a nice way to hook it to testing frameworks. It should just panic instead of requiring a fail function. There is an issue about that [here](https://github.com/onsi/gomega/issues/5).
While this is being discussed and hopefully fixed, the way to use Gomega with Goblin is:
```go
package foobar
import (
"testing"
. "github.com/franela/goblin"
. "github.com/onsi/gomega"
)
func Test(t *testing.T) {
g := Goblin(t)
//special hook for gomega
RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })
g.Describe("lala", func() {
g.It("lslslslsls", func() {
Expect(1).To(Equal(10))
})
})
}
```
FAQ:
----
### How do I run specific tests?
If `-goblin.run=$REGES` is supplied to the `go test` command then only tests that match the supplied regex will run
TODO:
-----
We do have a couple of [issues](https://github.com/franela/goblin/issues) pending we'll be addressing soon. But feel free to
contribute and send us PRs (with tests please :smile:).
Contributions:
------------
Special thanks to [Leandro Reox](https://github.com/leandroreox) (Leitan) for the goblin logo.

59
vendor/github.com/franela/goblin/assertions.go

@ -0,0 +1,59 @@
package goblin
import (
"fmt"
"reflect"
"strings"
)
type Assertion struct {
src interface{}
fail func(interface{})
}
func objectsAreEqual(a, b interface{}) bool {
if reflect.TypeOf(a) != reflect.TypeOf(b) {
return false
}
if reflect.DeepEqual(a, b) {
return true
}
if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
return true
}
return false
}
func formatMessages(messages ...string) string {
if len(messages) > 0 {
return ", " + strings.Join(messages, " ")
}
return ""
}
func (a *Assertion) Eql(dst interface{}) {
a.Equal(dst)
}
func (a *Assertion) Equal(dst interface{}) {
if !objectsAreEqual(a.src, dst) {
a.fail(fmt.Sprintf("%#v %s %#v", a.src, "does not equal", dst))
}
}
func (a *Assertion) IsTrue(messages ...string) {
if !objectsAreEqual(a.src, true) {
message := fmt.Sprintf("%v %s%s", a.src, "expected false to be truthy", formatMessages(messages...))
a.fail(message)
}
}
func (a *Assertion) IsFalse(messages ...string) {
if !objectsAreEqual(a.src, false) {
message := fmt.Sprintf("%v %s%s", a.src, "expected true to be falsey", formatMessages(messages...))
a.fail(message)
}
}

36
vendor/github.com/franela/goblin/go.snippets

@ -0,0 +1,36 @@
snippet gd
g.Describe("${1:name}", func() {
${2}
})
${0}
snippet git
g.It("${1:name}", func() {
${2}
})
${0}
snippet gait
g.It("${1:name}", func(done Done) {
done()
${2}
})
${0}
snippet gb
g.Before(func() {
${1}
})
${0}
snippet gbe
g.BeforeEach(func() {
${1}
})
${0}
snippet ga
g.After(func() {
${1}
})
${0}
snippet gae
g.AfterEach(func() {
${1}
})
${0}

302
vendor/github.com/franela/goblin/goblin.go

@ -0,0 +1,302 @@
package goblin
import (
"flag"
"fmt"
"regexp"
"runtime"
"sync"
"testing"
"time"
)
type Done func(error ...interface{})
type Runnable interface {
run(*G) bool
}
func (g *G) Describe(name string, h func()) {
d := &Describe{name: name, h: h, parent: g.parent}
if d.parent != nil {
d.parent.children = append(d.parent.children, Runnable(d))
}
g.parent = d
h()
g.parent = d.parent
if g.parent == nil && d.hasTests {
g.reporter.begin()
if d.run(g) {
g.t.Fail()
}
g.reporter.end()
}
}
func (g *G) Timeout(time time.Duration) {
g.timeout = time
g.timer.Reset(time)
}
type Describe struct {
name string
h func()
children []Runnable
befores []func()
afters []func()
afterEach []func()
beforeEach []func()
hasTests bool
parent *Describe
}
func (d *Describe) runBeforeEach() {
if d.parent != nil {
d.parent.runBeforeEach()
}
for _, b := range d.beforeEach {
b()
}
}
func (d *Describe) runAfterEach() {
if d.parent != nil {
d.parent.runAfterEach()
}
for _, a := range d.afterEach {
a()
}
}
func (d *Describe) run(g *G) bool {
failed := false
if d.hasTests {
g.reporter.beginDescribe(d.name)
for _, b := range d.befores {
b()
}
for _, r := range d.children {
if r.run(g) {
failed = true
}
}
for _, a := range d.afters {
a()
}
g.reporter.endDescribe()
}
return failed
}
type Failure struct {
stack []string
testName string
message string
}
type It struct {
h interface{}
name string
parent *Describe
failure *Failure
reporter Reporter
isAsync bool
}
func (it *It) run(g *G) bool {
g.currentIt = it
if it.h == nil {
g.reporter.itIsPending(it.name)
return false
}
//TODO: should handle errors for beforeEach
it.parent.runBeforeEach()
runIt(g, it.h)
it.parent.runAfterEach()
failed := false
if it.failure != nil {
failed = true
}
if failed {
g.reporter.itFailed(it.name)
g.reporter.failure(it.failure)
} else {
g.reporter.itPassed(it.name)
}
return failed
}
func (it *It) failed(msg string, stack []string) {
it.failure = &Failure{stack: stack, message: msg, testName: it.parent.name + " " + it.name}
}
func parseFlags() {
//Flag parsing
flag.Parse()
if *regexParam != "" {
runRegex = regexp.MustCompile(*regexParam)
} else {
runRegex = nil
}
}
var timeout = flag.Duration("goblin.timeout", 5*time.Second, "Sets default timeouts for all tests")
var isTty = flag.Bool("goblin.tty", true, "Sets the default output format (color / monochrome)")
var regexParam = flag.String("goblin.run", "", "Runs only tests which match the supplied regex")
var runRegex *regexp.Regexp
func init() {
parseFlags()
}
func Goblin(t *testing.T, arguments ...string) *G {
g := &G{t: t, timeout: *timeout}
var fancy TextFancier
if *isTty {
fancy = &TerminalFancier{}
} else {
fancy = &Monochrome{}
}
g.reporter = Reporter(&DetailedReporter{fancy: fancy})
return g
}
func runIt(g *G, h interface{}) {
defer timeTrack(time.Now(), g)
g.mutex.Lock()
g.timedOut = false
g.mutex.Unlock()
g.timer = time.NewTimer(g.timeout)
g.shouldContinue = make(chan bool)
if call, ok := h.(func()); ok {
// the test is synchronous
go func(c chan bool) { call(); c <- true }(g.shouldContinue)
} else if call, ok := h.(func(Done)); ok {
doneCalled := 0
go func(c chan bool) {
call(func(msg ...interface{}) {
if len(msg) > 0 {
g.Fail(msg)
} else {
doneCalled++
if doneCalled > 1 {
g.Fail("Done called multiple times")
}
c <- true
}
})
}(g.shouldContinue)
} else {
panic("Not implemented.")
}
select {
case <-g.shouldContinue:
case <-g.timer.C:
//Set to nil as it shouldn't continue
g.shouldContinue = nil
g.timedOut = true
g.Fail("Test exceeded " + fmt.Sprintf("%s", g.timeout))
}
// Reset timeout value
g.timeout = *timeout
}
type G struct {
t *testing.T
parent *Describe
currentIt *It
timeout time.Duration
reporter Reporter
timedOut bool
shouldContinue chan bool
mutex sync.Mutex
timer *time.Timer
}
func (g *G) SetReporter(r Reporter) {
g.reporter = r
}
func (g *G) It(name string, h ...interface{}) {
if matchesRegex(name) {
it := &It{name: name, parent: g.parent, reporter: g.reporter}
notifyParents(g.parent)
if len(h) > 0 {
it.h = h[0]
}
g.parent.children = append(g.parent.children, Runnable(it))
}
}
func matchesRegex(value string) bool {
if runRegex != nil {
return runRegex.MatchString(value)
}
return true
}
func notifyParents(d *Describe) {
d.hasTests = true
if d.parent != nil {
notifyParents(d.parent)
}
}
func (g *G) Before(h func()) {
g.parent.befores = append(g.parent.befores, h)
}
func (g *G) BeforeEach(h func()) {
g.parent.beforeEach = append(g.parent.beforeEach, h)
}
func (g *G) After(h func()) {
g.parent.afters = append(g.parent.afters, h)
}
func (g *G) AfterEach(h func()) {
g.parent.afterEach = append(g.parent.afterEach, h)
}
func (g *G) Assert(src interface{}) *Assertion {
return &Assertion{src: src, fail: g.Fail}
}
func timeTrack(start time.Time, g *G) {
g.reporter.itTook(time.Since(start))
}
func (g *G) Fail(error interface{}) {
//Skips 7 stacks due to the functions between the stack and the test
stack := ResolveStack(7)
message := fmt.Sprintf("%v", error)
g.currentIt.failed(message, stack)
if g.shouldContinue != nil {
g.shouldContinue <- true
}
g.mutex.Lock()
defer g.mutex.Unlock()
if !g.timedOut {
//Stop test function execution
runtime.Goexit()
}
}

BIN
vendor/github.com/franela/goblin/goblin_logo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
vendor/github.com/franela/goblin/goblin_output.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

26
vendor/github.com/franela/goblin/mono_reporter.go

@ -0,0 +1,26 @@
package goblin
import ()
type Monochrome struct {
}
func (self *Monochrome) Red(text string) string {
return "!" + text
}
func (self *Monochrome) Gray(text string) string {
return text
}
func (self *Monochrome) Cyan(text string) string {
return text
}
func (self *Monochrome) WithCheck(text string) string {
return ">>>" + text
}
func (self *Monochrome) Green(text string) string {
return text
}

137
vendor/github.com/franela/goblin/reporting.go

@ -0,0 +1,137 @@
package goblin
import (
"fmt"
"strconv"
"strings"
"time"
)
type Reporter interface {
beginDescribe(string)
endDescribe()
begin()
end()
failure(*Failure)
itTook(time.Duration)
itFailed(string)
itPassed(string)
itIsPending(string)
}
type TextFancier interface {
Red(text string) string
Gray(text string) string
Cyan(text string) string
Green(text string) string
WithCheck(text string) string
}
type DetailedReporter struct {
level, failed, passed, pending int
failures []*Failure
executionTime, totalExecutionTime time.Duration
fancy TextFancier
}
func (r *DetailedReporter) SetTextFancier(f TextFancier) {
r.fancy = f
}
type TerminalFancier struct {
}
func (self *TerminalFancier) Red(text string) string {
return "\033[31m" + text + "\033[0m"
}
func (self *TerminalFancier) Gray(text string) string {
return "\033[90m" + text + "\033[0m"
}
func (self *TerminalFancier) Cyan(text string) string {
return "\033[36m" + text + "\033[0m"
}
func (self *TerminalFancier) Green(text string) string {
return "\033[32m" + text + "\033[0m"
}
func (self *TerminalFancier) WithCheck(text string) string {
return "\033[32m\u2713\033[0m " + text
}
func (r *DetailedReporter) getSpace() string {
return strings.Repeat(" ", (r.level+1)*2)
}
func (r *DetailedReporter) failure(failure *Failure) {
r.failures = append(r.failures, failure)
}
func (r *DetailedReporter) print(text string) {
fmt.Printf("%v%v\n", r.getSpace(), text)
}
func (r *DetailedReporter) printWithCheck(text string) {
fmt.Printf("%v%v\n", r.getSpace(), r.fancy.WithCheck(text))
}
func (r *DetailedReporter) beginDescribe(name string) {
fmt.Println("")
r.print(name)
r.level++
}
func (r *DetailedReporter) endDescribe() {
r.level--
}
func (r *DetailedReporter) itTook(duration time.Duration) {
r.executionTime = duration
r.totalExecutionTime += duration
}
func (r *DetailedReporter) itFailed(name string) {
r.failed++
r.print(r.fancy.Red(strconv.Itoa(r.failed) + ") " + name))
}
func (r *DetailedReporter) itPassed(name string) {
r.passed++
r.printWithCheck(r.fancy.Gray(name))
}
func (r *DetailedReporter) itIsPending(name string) {
r.pending++
r.print(r.fancy.Cyan("- " + name))
}
func (r *DetailedReporter) begin() {
}
func (r *DetailedReporter) end() {
comp := fmt.Sprintf("%d tests complete", r.passed)
t := fmt.Sprintf("(%d ms)", r.totalExecutionTime/time.Millisecond)
//fmt.Printf("\n\n \033[32m%d tests complete\033[0m \033[90m(%d ms)\033[0m\n", r.passed, r.totalExecutionTime/time.Millisecond)
fmt.Printf("\n\n %v %v\n", r.fancy.Green(comp), r.fancy.Gray(t))
if r.pending > 0 {
pend := fmt.Sprintf("%d test(s) pending", r.pending)
fmt.Printf(" %v\n\n", r.fancy.Cyan(pend))
}
if len(r.failures) > 0 {
fmt.Printf("%s \n\n", r.fancy.Red(fmt.Sprintf(" %d tests failed:", len(r.failures))))
}
for i, failure := range r.failures {
fmt.Printf(" %d) %s:\n\n", i+1, failure.testName)
fmt.Printf(" %s\n", r.fancy.Red(failure.message))
for _, stackItem := range failure.stack {
fmt.Printf(" %s\n", r.fancy.Gray(stackItem))
}
}
}

21
vendor/github.com/franela/goblin/resolver.go

@ -0,0 +1,21 @@
package goblin
import (
"runtime/debug"
"strings"
)
func ResolveStack(skip int) []string {
return cleanStack(debug.Stack(), skip)
}
func cleanStack(stack []byte, skip int) []string {
arrayStack := strings.Split(string(stack), "\n")
var finalStack []string
for i := skip; i < len(arrayStack); i++ {
if strings.Contains(arrayStack[i], ".go") {
finalStack = append(finalStack, arrayStack[i])
}
}
return finalStack
}

8
vendor/vendor.json

@ -144,6 +144,12 @@
"revision": "c0d7d3282e4c14991a4814de7eae4774e388de61", "revision": "c0d7d3282e4c14991a4814de7eae4774e388de61",
"revisionTime": "2016-10-07T22:43:33Z" "revisionTime": "2016-10-07T22:43:33Z"
}, },
{
"checksumSHA1": "ip3Xz/dILw2RMM6Z0MzAj5TUZ/c=",
"path": "github.com/franela/goblin",
"revision": "2fa789fd0c6b7975acbfb89a04830b4081a7b0e9",
"revisionTime": "2017-01-11T05:10:28Z"
},
{ {
"checksumSHA1": "cVyhKIRI2gQrgpn5qrBeAqErmWM=", "checksumSHA1": "cVyhKIRI2gQrgpn5qrBeAqErmWM=",
"path": "github.com/go-ini/ini", "path": "github.com/go-ini/ini",
@ -175,5 +181,5 @@
"revisionTime": "2016-10-06T02:47:49Z" "revisionTime": "2016-10-06T02:47:49Z"
} }
], ],
"rootPath": "github.com/drone-plugins/drone-terraform" "rootPath": "github.com/jmccann/drone-terraform"
} }

Loading…
Cancel
Save