grim/convey

Parents c43b78499c77
Children 4c579ae789aa
Remove the convey/extend task as it's normal usage is already covered by plan/stage environment variables. It's corner case, expanding variables, is rather exotic and not something that comes up often.
--- a/ChangeLog Sat Oct 26 13:45:42 2019 -0500
+++ b/ChangeLog Sat Oct 26 13:53:24 2019 -0500
@@ -33,6 +33,8 @@
--list-meta-plans, --list-plans, --list-tasks, and --config.
* Removed the network since it doesn't actually protect the host from the
container.
+ * Removed the convey/extend task as it's very normal case is easily
+ replicated by plan/stage environment variables.
0.13.1: 20180114
* Write warning, error, and fatal log messages to stderr. Fixed #156
--- a/go.mod Sat Oct 26 13:45:42 2019 -0500
+++ b/go.mod Sat Oct 26 13:53:24 2019 -0500
@@ -14,7 +14,6 @@
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-zglob v0.0.1
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f
github.com/satori/go.uuid v1.2.0
github.com/sirupsen/logrus v1.4.1
--- a/go.sum Sat Oct 26 13:45:42 2019 -0500
+++ b/go.sum Sat Oct 26 13:53:24 2019 -0500
@@ -32,8 +32,6 @@
github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f h1:WyCn68lTiytVSkk7W1K9nBiSGTSRlUOdyTnSjwrIlok=
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
--- a/loaders/convey/extend_test.go Sat Oct 26 13:45:42 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,442 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package convey
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-
- cConfig "bitbucket.org/rw_grim/convey/config"
- "bitbucket.org/rw_grim/convey/tasks"
-)
-
-// This test suite tests
-
-func TestExtendSimple(t *testing.T) {
- data := `
-tasks:
- a:
- type: docker/run
- image: alpine:3.6
- environment:
- - X=1
- - Y=2
- b:
- type: convey/extend
- task: a
- environment:
- - X=3
-plans:
- default:
- stages:
- - tasks: [a, b]
-`
-
- loader := &Loader{}
- cfg, err := loader.Load(".", ".", []byte(data), []string{}, true)
-
- assert.Nil(t, err)
- assert.Len(t, cfg.Tasks, 2)
- assert.Contains(t, cfg.Tasks, "a")
- assert.Contains(t, cfg.Tasks, "b")
- assert.Exactly(t, cfg.Tasks["b"].(*tasks.Extend).InnerTask, cfg.Tasks["a"])
-}
-
-func TestExtendChain(t *testing.T) {
- data := `
-tasks:
- a:
- type: docker/run
- image: alpine:3.6
- environment:
- - X=1
- - Y=2
- b:
- type: convey/extend
- task: a
- environment:
- - X=3
- c:
- type: convey/extend
- task: b
- environment:
- - X=4
-plans:
- default:
- stages:
- - tasks: [a, b, c]
-`
-
- loader := &Loader{}
- cfg, err := loader.Load(".", ".", []byte(data), []string{}, true)
-
- assert.Nil(t, err)
- assert.Len(t, cfg.Tasks, 3)
- assert.Contains(t, cfg.Tasks, "a")
- assert.Contains(t, cfg.Tasks, "b")
- assert.Contains(t, cfg.Tasks, "c")
- assert.Exactly(
- t,
- cfg.Tasks["c"].(*tasks.Extend).InnerTask,
- cfg.Tasks["b"],
- )
- assert.Exactly(
- t,
- cfg.Tasks["b"].(*tasks.Extend).InnerTask,
- cfg.Tasks["a"],
- )
- assert.Exactly(
- t,
- cfg.Tasks["c"].(*tasks.Extend).InnerTask.(*tasks.Extend).InnerTask,
- cfg.Tasks["a"],
- )
-}
-
-func TestExtendCycle(t *testing.T) {
- data := `
-tasks:
- a:
- type: convey/extend
- task: b
- b:
- type: convey/extend
- task: a
-plans:
- default:
- stages:
- - tasks: [a, b]
-`
-
- loader := &Loader{}
- _, err := loader.Load(".", ".", []byte(data), []string{}, true)
-
- assert.EqualError(
- t,
- err,
- "The following tasks are part of a dependency cycle: a, b",
- )
-}
-
-func TestExtendMissingTask(t *testing.T) {
- data := `
-tasks:
- b:
- type: convey/extend
- task: a
-plans:
- default:
- stages:
- - tasks: [a, b]
-`
-
- loader := &Loader{}
- _, err := loader.Load(".", ".", []byte(data), []string{}, true)
-
- assert.EqualError(t, err, "b: Extending undeclared task 'a'")
-}
-
-func TestExtendExtends(t *testing.T) {
- baseData := `
-environment:
- - x=1
-tasks:
- foo:
- type: docker/run
- image: imaginary
- environment:
- - x=2
-`
-
- extendedData := `
-extends: base.yaml
-environment:
- - x=3
-tasks:
- bar:
- type: convey/extend
- task: foo
- environment:
- - x=3
-plans:
- plan:
- stages:
- - tasks: [foo, bar]
-`
-
- loader := &Loader{
- fileLoader: func(name string, c *Loader) (*cConfig.Config, error) {
- return c.Load(".", name, []byte(baseData), []string{}, true)
- },
- }
-
- cfg, err := loader.Load(".", ".", []byte(extendedData), []string{}, true)
-
- assert.Nil(t, err)
- assert.Len(t, cfg.Tasks, 2)
- assert.Contains(t, cfg.Tasks, "foo")
- assert.Contains(t, cfg.Tasks, "bar")
- assert.Exactly(
- t,
- cfg.Tasks["bar"].(*tasks.Extend).InnerTask,
- cfg.Tasks["foo"],
- )
-}
-
-func TestReplaceStage(t *testing.T) {
- data1 := `
-tasks:
- pre:
- type: docker/run
- image: pre
- post:
- type: docker/run
- image: post
- foo:
- type: docker/run
- image: foo
-plans:
- plan1:
- stages:
- - name: pre
- tasks:
- - pre
- - name: real-work
- tasks:
- - foo
- - name: post
- tasks:
- - post
- plan2:
- stages:
- - tasks:
- - pre
- - foo
- - post
-`
-
- data2 := `
-extends: base1.yaml
-tasks:
- bar:
- type: docker/run
- image: bar
-plans:
- plan1:
- merge: true
- stages:
- - name: real-work
- tasks:
- - bar
- plan2:
- stages:
- - name: real-work
- tasks:
- - bar
-`
-
- data3 := `
-extends: base2.yaml
-tasks:
- baz:
- type: docker/run
- image: baz
-plans:
- plan1:
- merge: true
- stages:
- - name: post
- tasks:
- - baz
-`
-
- loader := &Loader{
- fileLoader: func(name string, c *Loader) (*cConfig.Config, error) {
- m := map[string]string{
- "base1.yaml": data1,
- "base2.yaml": data2,
- }
-
- return c.Load(".", name, []byte(m[name]), []string{}, true)
- },
- }
-
- cfg, err := loader.Load(".", ".", []byte(data3), []string{}, true)
-
- assert.Nil(t, err)
- assert.Len(t, cfg.Plans, 2)
- assert.Contains(t, cfg.Plans, "plan1")
- assert.Contains(t, cfg.Plans, "plan2")
-
- assert.Len(t, cfg.Plans["plan1"].Stages, 3)
- assert.Equal(t, cfg.Plans["plan1"].Stages[0].Name, "pre")
- assert.Equal(t, cfg.Plans["plan1"].Stages[1].Name, "real-work")
- assert.Equal(t, cfg.Plans["plan1"].Stages[2].Name, "post")
- assert.Len(t, cfg.Plans["plan1"].Stages[0].Tasks, 1)
- assert.Len(t, cfg.Plans["plan1"].Stages[1].Tasks, 1)
- assert.Len(t, cfg.Plans["plan1"].Stages[2].Tasks, 1)
- assert.ElementsMatch(
- t,
- cfg.Plans["plan1"].Stages[0].Tasks,
- []string{"pre"},
- )
- assert.ElementsMatch(
- t,
- cfg.Plans["plan1"].Stages[1].Tasks,
- []string{"bar"},
- )
- assert.ElementsMatch(
- t,
- cfg.Plans["plan1"].Stages[2].Tasks,
- []string{"baz"},
- )
-
- assert.Len(t, cfg.Plans["plan2"].Stages, 1)
- assert.Len(t, cfg.Plans["plan2"].Stages[0].Tasks, 1)
- assert.ElementsMatch(
- t,
- cfg.Plans["plan2"].Stages[0].Tasks,
- []string{"bar"},
- )
-}
-
-func TestMergeMissingPlan(t *testing.T) {
- data1 := `
-tasks:
- foo:
- type: docker/run
- image: foo
-plans:
- plan1:
- stages:
- - tasks: [foo]
-`
-
- data2 := `
-extends: base1.yaml
-tasks:
- bar:
- type: docker/run
- image: bar
-plans:
- plan2:
- merge: true
- stages:
- - tasks: [foo, bar]
-`
-
- loader := &Loader{
- fileLoader: func(name string, c *Loader) (*cConfig.Config, error) {
- return c.Load(".", name, []byte(data1), []string{}, true)
- },
- }
-
- _, err := loader.Load(".", ".", []byte(data2), []string{}, true)
-
- assert.EqualError(t, err, "cannot merge with unknown plan 'plan2'")
-}
-
-func TestMergeMissingStage(t *testing.T) {
- data1 := `
-tasks:
- foo:
- type: docker/run
- image: foo
-plans:
- plan1:
- stages:
- - name: only
- tasks:
- - foo
-`
-
- data2 := `
-extends: base1.yaml
-tasks:
- bar:
- type: docker/run
- image: bar
-plans:
- plan1:
- merge: true
- stages:
- - name: missing
- tasks:
- - bar
-`
-
- loader := &Loader{
- fileLoader: func(name string, c *Loader) (*cConfig.Config, error) {
- return c.Load(".", name, []byte(data1), []string{}, true)
- },
- }
-
- _, err := loader.Load(".", ".", []byte(data2), []string{}, true)
-
- assert.EqualError(
- t,
- err,
- "cannot overwrite stage 'missing' in plan 'plan1' (no such stage in parent)",
- )
-}
-
-func TestMergePlanEnvironment(t *testing.T) {
- data1 := `
-tasks:
- foo:
- type: docker/run
- image: foo
-plans:
- plan1:
- stages:
- - name: only
- tasks:
- - foo
- environment:
- - FOO=BAR
- - BAR=BAZ
-`
-
- data2 := `
-extends: base1.yaml
-plans:
- plan1:
- merge: true
- environment:
- - BAR=BONK
-`
-
- loader := &Loader{
- fileLoader: func(name string, c *Loader) (*cConfig.Config, error) {
- return c.Load(".", name, []byte(data1), []string{}, true)
- },
- }
-
- cfg, err := loader.Load(".", ".", []byte(data2), []string{}, true)
-
- assert.Nil(t, err)
- assert.ElementsMatch(
- t,
- cfg.Plans["plan1"].Stages[0].Tasks,
- []string{"foo"},
- )
- assert.ElementsMatch(
- t,
- cfg.Plans["plan1"].Environment,
- []string{"FOO=BAR", "BAR=BONK"},
- )
-}
--- a/tasks/README.md Sat Oct 26 13:45:42 2019 -0500
+++ b/tasks/README.md Sat Oct 26 13:53:24 2019 -0500
@@ -23,54 +23,6 @@
----
-## convey/extend Task
-
-An convey/extend task overrides the environment of another task.
-
-### Attributes
-
-| Name | Required | Default | Description |
-| ---------------- | -------- | ------- | ----------- |
-| environment | | | The override environment |
-| expand | | | The envvars which can be expanded into lists on use |
-| expand_delimiter | | ; | The string to split mapped values by |
-| task | Yes | | The name of the task to extend |
-
-The `expand` and `expand_delimiter` attributes allow an environment variable, which is an unstructured string, to act as if it is an array. This is useful for supplying an "abstract" parent task with several arguments for the same attribute (e.g. tags in a build task). Variables that occur in the environment with a name in expand will be split by the expand delimiter to form a list, where applicable.
-
-### Example
-
- greeting:
- type: docker/run
- image: gliderlabs/alpine:edge
- script:
- - echo "${MESSAGE}"
- environment:
- - MESSAGE="Hello, World"
-
- informal-greeting:
- type: convey/extend
- task: greeting
- environment:
- - MESSAGE="Hi!"
-
-### Example with Variable Expansion
-
- tag-alpine:
- type: docker/tag
- source: gliderlabs/alpine:edge
- destinations: ${TAGS}
-
- tag-concrete:
- type: convey/extend
- task: tag-alpine
- environment:
- - TAGS=foo;bar;baz
- expand:
- - TAGS
-
-----
-
## convey/noop Task
A noop task does nothing. It is a "No Operation" task. It's used primarily in
--- a/tasks/extend.go Sat Oct 26 13:45:42 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package tasks
-
-import (
- "fmt"
-
- "github.com/mohae/deepcopy"
- log "github.com/sirupsen/logrus"
-
- "bitbucket.org/rw_grim/convey/environment"
- "bitbucket.org/rw_grim/convey/runtime"
- "bitbucket.org/rw_grim/convey/yaml"
-)
-
-// Extend represents a task that extends another task.
-type Extend struct {
- Environment yaml.StringOrSlice `yaml:"environment"`
- Expand yaml.StringOrSlice `yaml:"expand"`
- ExpandDelimiter string `yaml:"expand_delimiter"`
- Task string `yaml:"task"`
-
- // A copy of the extended task. Must be public so that deepcopy
- // can serialize it properly in case an extended task is extended
- // itself (when private the innerTask is nil and causes a bad
- // data access exception).
- InnerTask Task
-}
-
-// Execute runs an extended task.
-func (e *Extend) Execute(name string, logger *log.Entry, env *environment.Environment, rt *runtime.Runtime) error {
- // While extending, certain environment variables can be expanded into
- // lists. We store this meta information as a stack on the state, which
- // is passed into the inner task execute method (and so on).
-
- newRt := runtime.NewWithEnvironment(
- rt.State,
- environment.NewExpandable(
- e.Expand, e.ExpandDelimiter,
- environment.Merge(e.Environment, rt.Environment.Items())...,
- ),
- )
-
- return e.InnerTask.Execute(name, logger, env, newRt)
-}
-
-// New creates a new extend task.
-func (e *Extend) New() Task {
- return &Extend{}
-}
-
-// Valid validates the task.
-func (e *Extend) Valid() error {
- if e.ExpandDelimiter == "" {
- e.ExpandDelimiter = ";"
- }
-
- return nil
-}
-
-// Dependencies returns a list of tasks that this task depends on.
-func (e *Extend) Dependencies() []string {
- return []string{e.Task}
-}
-
-// Resolve returns the fully extended task.
-func (e *Extend) Resolve(taskMap map[string]Task) error {
- task, ok := taskMap[e.Task]
- if !ok {
- // Should never happen due to dependency order
- return fmt.Errorf("Extending undeclared task '%s'", e.Task)
- }
-
- // Some tasks may set their own fields, e.g. when mapping things
- // to the correct runtime environment. In order to make sure that
- // the inner task doesn't cache something from another run, we
- // do a clone of the task here so we get our own copy to muck with.
-
- e.InnerTask = deepcopy.Copy(task).(Task)
- return nil
-}
--- a/tasks/extend_test.go Sat Oct 26 13:45:42 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-// Convey
-// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package tasks
-
-import (
- "testing"
-
- log "github.com/sirupsen/logrus"
- "github.com/stretchr/testify/assert"
-
- "bitbucket.org/rw_grim/convey/environment"
- "bitbucket.org/rw_grim/convey/runtime"
- "bitbucket.org/rw_grim/convey/state"
-)
-
-func TestExtendExecute(t *testing.T) {
- var (
- task = newMockTask()
- fullEnv = environment.New()
- )
-
- env := environment.New()
- env.MergeSlice([]string{"bar=bonk", "quux=honk"})
- rt := runtime.NewWithEnvironment(&state.State{}, env)
-
- task.executeFn = func(name string, logger *log.Entry, env *environment.Environment, rt *runtime.Runtime) error {
- fullEnv.Merge(env).MergeSlice([]string{"x=1", "foo=quux"}).Merge(rt.Environment)
- return nil
- }
-
- c := &Extend{
- InnerTask: task,
- Environment: []string{"foo=bar", "bar=baz"},
- }
-
- assert.Nil(t, c.Execute("task", nil, environment.New(), rt))
- assert.Len(t, fullEnv.Items(), 4)
- assert.ElementsMatch(
- t,
- fullEnv.Items(),
- []string{"x=1", "foo=bar", "bar=bonk", "quux=honk"},
- )
-
- // Should revert state
- assert.Len(t, env.Items(), 2)
- assert.ElementsMatch(
- t,
- env.Items(),
- []string{"bar=bonk", "quux=honk"},
- )
-}
-
-func TestExtendDependencies(t *testing.T) {
- c := &Extend{Task: "test-task"}
-
- assert.Equal(t, c.Dependencies(), []string{"test-task"})
-}
-
-func TestExtendResolve(t *testing.T) {
- task := newMockTask()
- task.X = 3
- task.Y = []string{"foo", "bar"}
- task.Z = struct {
- A string
- B string
- C string
- }{
- A: "wynken",
- B: "blynken",
- C: "nod",
- }
-
- c := &Extend{Task: "a"}
- err := c.Resolve(map[string]Task{
- "a": task,
- })
-
- assert.Nil(t, err)
-
- // Must clone inner task
- assert.NotNil(t, c.InnerTask)
- assert.NotEqual(t, c.InnerTask, task)
- assert.Equal(t, c.InnerTask.(*mockTask).X, 3)
- assert.Equal(t, c.InnerTask.(*mockTask).Y, []string{"foo", "bar"})
- assert.Equal(t, c.InnerTask.(*mockTask).Z.A, "wynken")
- assert.Equal(t, c.InnerTask.(*mockTask).Z.B, "blynken")
- assert.Equal(t, c.InnerTask.(*mockTask).Z.C, "nod")
-}
-
-func TestExtendResolveChain(t *testing.T) {
- task := newMockTask()
- task.X = 3
- task.Y = []string{"foo", "bar"}
-
- c1 := &Extend{Task: "a"}
- c2 := &Extend{Task: "b"}
- taskMapping := map[string]Task{
- "a": task,
- "b": c1,
- }
-
- assert.Nil(t, c1.Resolve(taskMapping))
- assert.Nil(t, c2.Resolve(taskMapping))
-
- // Must clone inner task
- assert.NotNil(t, c2.InnerTask)
- assert.NotNil(t, c2.InnerTask.(*Extend).InnerTask)
- assert.Equal(t, c2.InnerTask.(*Extend).InnerTask.(*mockTask).X, 3)
- assert.Equal(
- t,
- c2.InnerTask.(*Extend).InnerTask.(*mockTask).Y,
- []string{"foo", "bar"},
- )
-}
-
-//
-// Mocks
-
-type mockTask struct {
- X int
- Y []string
- Z struct {
- A string
- B string
- C string
- }
-
- executeFn func(string, *log.Entry, *environment.Environment, *runtime.Runtime) error
-}
-
-func newMockTask() *mockTask {
- return &mockTask{
- executeFn: func(string, *log.Entry, *environment.Environment, *runtime.Runtime) error {
- return nil
- },
- }
-}
-
-func (t *mockTask) Execute(name string, logger *log.Entry, env *environment.Environment, rt *runtime.Runtime) error {
- return t.executeFn(name, logger, env, rt)
-}
-
-func (t *mockTask) New() Task {
- return &mockTask{}
-}
-
-func (t *mockTask) Valid() error {
- return nil
-}
--- a/tasks/tasks.go Sat Oct 26 13:45:42 2019 -0500
+++ b/tasks/tasks.go Sat Oct 26 13:53:24 2019 -0500
@@ -29,7 +29,6 @@
Tasks = map[string]Task{
"clean": &Clean{},
"export": &Export{},
- "extend": &Extend{},
"import": &Import{},
"noop": &Noop{},
}