mirror of
https://github.com/thegeeklab/wp-opentofu.git
synced 2024-11-10 04:10:41 +00:00
commit
4423c336c5
64
DOCS.md
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
|
||||||
|
|
||||||
|
@ -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
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))
|
||||||
}
|
}
|
||||||
|
@ -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
generated
vendored
Normal file
19
vendor/github.com/franela/goblin/LICENSE
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
3
vendor/github.com/franela/goblin/Makefile
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export GOPATH=$(shell pwd)
|
||||||
|
test:
|
||||||
|
go test -v
|
141
vendor/github.com/franela/goblin/README.md
generated
vendored
Normal file
141
vendor/github.com/franela/goblin/README.md
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
59
vendor/github.com/franela/goblin/assertions.go
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
36
vendor/github.com/franela/goblin/go.snippets
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
302
vendor/github.com/franela/goblin/goblin.go
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
BIN
vendor/github.com/franela/goblin/goblin_logo.jpg
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
vendor/github.com/franela/goblin/goblin_output.png
generated
vendored
Normal file
BIN
vendor/github.com/franela/goblin/goblin_output.png
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
26
vendor/github.com/franela/goblin/mono_reporter.go
generated
vendored
Normal file
26
vendor/github.com/franela/goblin/mono_reporter.go
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
137
vendor/github.com/franela/goblin/reporting.go
generated
vendored
Normal file
@ -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
generated
vendored
Normal file
21
vendor/github.com/franela/goblin/resolver.go
generated
vendored
Normal file
@ -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
vendored
8
vendor/vendor.json
vendored
@ -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…
Reference in New Issue
Block a user