diff --git a/DOCS.md b/DOCS.md index 63d97f5..adf12d8 100644 --- a/DOCS.md +++ b/DOCS.md @@ -29,8 +29,11 @@ pipeline: + app_version: 1.0.0 ``` -Example configuration passing secrets to terraform via `vars`. The following -example will call `terraform apply -var my_secret=${TERRAFORM_SECRET}`: +Example configuration passing secrets to terraform. Please read +https://www.terraform.io/docs/configuration/variables.html#environment-variables +for more details. + +**Drone 0.6+**: ```diff pipeline: @@ -38,7 +41,26 @@ pipeline: image: jmccann/drone-terraform:1 plan: false + 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 @@ -138,36 +160,6 @@ pipeline: + 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. ```yaml @@ -205,12 +197,6 @@ var_files : a list of variable files to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `-var-file ` 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 =$` -* Additionally each entry generate sets and envvar as follows: `key=$value` - ca_cert : ca cert to add to your environment to allow terraform to use internal/private resources @@ -227,4 +213,4 @@ parallelism : The number of concurrent operations as Terraform walks its graph. destroy (boolean) -: Destroys the service (still requires [`force_destroy`](https://www.terraform.io/docs/providers/fastly/r/service_v1.html#force_destroy) option to be set in the service definition) \ No newline at end of file +: Destroys the service (still requires [`force_destroy`](https://www.terraform.io/docs/providers/fastly/r/service_v1.html#force_destroy) option to be set in the service definition) diff --git a/Dockerfile b/Dockerfile index 81dc427..214ff78 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # 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 COPY ./*.go ./src/ COPY ./vendor/ ./src/ diff --git a/plugin.go b/plugin.go index 4cd9f55..093e321 100644 --- a/plugin.go +++ b/plugin.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "os/exec" + "regexp" "strings" "time" @@ -53,9 +54,7 @@ func (p Plugin) Exec() error { var commands []*exec.Cmd - if len(p.Config.Secrets) != 0 { - exportSecrets(p.Config.Secrets) - } + CopyTfEnv() if 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) { - for k, v := range secrets { - os.Setenv(fmt.Sprintf("%s", k), fmt.Sprintf("%s", os.Getenv(v))) +func CopyTfEnv() { + tfVar := regexp.MustCompile(`^TF_VAR_.*$`) + 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, 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 { args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism)) } diff --git a/plugin_test.go b/plugin_test.go index d7cc9da..6073d9c 100644 --- a/plugin_test.go +++ b/plugin_test.go @@ -1,9 +1,12 @@ package main import ( + "os" "os/exec" "reflect" "testing" + + . "github.com/franela/goblin" ) 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==") + }) + }) +} diff --git a/vendor/github.com/franela/goblin/LICENSE b/vendor/github.com/franela/goblin/LICENSE new file mode 100644 index 0000000..b2d6522 --- /dev/null +++ b/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. diff --git a/vendor/github.com/franela/goblin/Makefile b/vendor/github.com/franela/goblin/Makefile new file mode 100644 index 0000000..66763dc --- /dev/null +++ b/vendor/github.com/franela/goblin/Makefile @@ -0,0 +1,3 @@ +export GOPATH=$(shell pwd) +test: + go test -v diff --git a/vendor/github.com/franela/goblin/README.md b/vendor/github.com/franela/goblin/README.md new file mode 100644 index 0000000..a4b6eab --- /dev/null +++ b/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. diff --git a/vendor/github.com/franela/goblin/assertions.go b/vendor/github.com/franela/goblin/assertions.go new file mode 100644 index 0000000..5ccae7d --- /dev/null +++ b/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) + } +} diff --git a/vendor/github.com/franela/goblin/go.snippets b/vendor/github.com/franela/goblin/go.snippets new file mode 100644 index 0000000..5610a4b --- /dev/null +++ b/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} diff --git a/vendor/github.com/franela/goblin/goblin.go b/vendor/github.com/franela/goblin/goblin.go new file mode 100644 index 0000000..d237d81 --- /dev/null +++ b/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() + } + +} diff --git a/vendor/github.com/franela/goblin/goblin_logo.jpg b/vendor/github.com/franela/goblin/goblin_logo.jpg new file mode 100644 index 0000000..44534f2 Binary files /dev/null and b/vendor/github.com/franela/goblin/goblin_logo.jpg differ diff --git a/vendor/github.com/franela/goblin/goblin_output.png b/vendor/github.com/franela/goblin/goblin_output.png new file mode 100644 index 0000000..be3c9ea Binary files /dev/null and b/vendor/github.com/franela/goblin/goblin_output.png differ diff --git a/vendor/github.com/franela/goblin/mono_reporter.go b/vendor/github.com/franela/goblin/mono_reporter.go new file mode 100644 index 0000000..04d6e5e --- /dev/null +++ b/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 +} diff --git a/vendor/github.com/franela/goblin/reporting.go b/vendor/github.com/franela/goblin/reporting.go new file mode 100644 index 0000000..1d67d66 --- /dev/null +++ b/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)) + } + } +} diff --git a/vendor/github.com/franela/goblin/resolver.go b/vendor/github.com/franela/goblin/resolver.go new file mode 100644 index 0000000..125fcec --- /dev/null +++ b/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 +} diff --git a/vendor/vendor.json b/vendor/vendor.json index b753746..3c62460 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -144,6 +144,12 @@ "revision": "c0d7d3282e4c14991a4814de7eae4774e388de61", "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=", "path": "github.com/go-ini/ini", @@ -175,5 +181,5 @@ "revisionTime": "2016-10-06T02:47:49Z" } ], - "rootPath": "github.com/drone-plugins/drone-terraform" + "rootPath": "github.com/jmccann/drone-terraform" }