Move plans to the runtime package
--- a/config/config.go Thu Dec 23 09:18:29 2021 -0600
+++ b/config/config.go Thu Dec 23 09:31:26 2021 -0600
@@ -22,14 +22,13 @@
log "github.com/sirupsen/logrus"
- "keep.imfreedom.org/grim/convey/plans"
"keep.imfreedom.org/grim/convey/runtime"
// Config represents a full convey configuration.
Tasks map[string]runtime.Task
- Plans map[string]plans.Plan
+ Plans map[string]runtime.Plan MetaPlans map[string]runtime.MetaPlan
--- a/config/raw.go Thu Dec 23 09:18:29 2021 -0600
+++ b/config/raw.go Thu Dec 23 09:31:26 2021 -0600
@@ -5,7 +5,6 @@
- "keep.imfreedom.org/grim/convey/plans"
"keep.imfreedom.org/grim/convey/runtime"
"keep.imfreedom.org/grim/convey/tasks"
@@ -13,7 +12,7 @@
Tasks map[string]yaml.MapSlice
- Plans map[string]plans.Plan
+ Plans map[string]runtime.Plan MetaPlans map[string]runtime.MetaPlan `yaml:"meta-plans"`
--- a/plans/plans.go Thu Dec 23 09:18:29 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-// 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 plans contains the plans structure.
- log "github.com/sirupsen/logrus"
- "keep.imfreedom.org/grim/convey/environment"
- "keep.imfreedom.org/grim/convey/logging"
- "keep.imfreedom.org/grim/convey/runtime"
- "keep.imfreedom.org/grim/convey/yaml"
- // ErrNoStages is an error that can be returned from Plan.Valid.
- ErrNoStages = errors.New("no stages found")
-// Plan is the representation of a Plan.
- Environment yaml.StringOrSlice `yaml:"environment"`
- Stages []runtime.Stage `yaml:"stages"`
-// Execute runs the plan.
-func (p *Plan) Execute(path string, configEnv environment.Environment, rt *runtime.Runtime) error {
- if err := p.Valid(); err != nil {
- planEnv := configEnv.Copy().MergeSlice(p.Environment).Merge(rt.Environment)
- p.logger = logging.NewAdapter(path)
- // set a flag on whether or not we've failed
- for idx, stage := range p.Stages {
- absStageName = fmt.Sprintf("%s/%s", path, stage.Name)
- absStageName = fmt.Sprintf("%s/%d", path, idx)
- stageLogger := logging.NewAdapter(absStageName)
- if stage.ShouldRun(planErr) {
- stageLogger.Info("stage starting")
- err := stage.Execute(absStageName, stageLogger, planEnv, rt)
- elapsed := time.Since(start)
- p.logger.Debugf("remaining plantime: %s", rt.Timeout)
- stageLogger.Error("stage failed")
- stageLogger.Infof("stage finished [%s]", elapsed.Round(10*time.Millisecond))
-// Valid validates the plan.
-func (p *Plan) Valid() error {
- if len(p.Stages) == 0 {
--- a/plans/plans_test.go Thu Dec 23 09:18:29 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-// 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/>.
- "github.com/stretchr/testify/assert"
- cYaml "keep.imfreedom.org/grim/convey/yaml"
-func unmarshal(t *testing.T, data string) Plan {
- err := yaml.Unmarshal([]byte(data), &p)
-func TestEnvironmentSlice(t *testing.T) {
- p := unmarshal(t, data)
- assert.Equal(t, p.Environment, cYaml.StringOrSlice{"foo=bar", "baz"})
-func TestEnvironmentString(t *testing.T) {
- data := `environment: foo=bar
- p := unmarshal(t, data)
- assert.Equal(t, p.Environment, cYaml.StringOrSlice{"foo=bar"})
-func TestStagesRequired(t *testing.T) {
- assert.EqualError(t, err, ErrNoStages.Error())
- assert.Len(t, p.Stages, 0)
-func TestValid(t *testing.T) {
- p := unmarshal(t, data)
- assert.Nil(t, p.Valid())
--- a/plans/stages_test.go Thu Dec 23 09:18:29 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-// 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/>.
- "github.com/stretchr/testify/assert"
- "keep.imfreedom.org/grim/convey/environment"
- "keep.imfreedom.org/grim/convey/runtime"
- "keep.imfreedom.org/grim/convey/tasks"
-func runPlan(path string, p Plan, tasks map[string]runtime.Task) error {
- env := environment.New()
- rt := runtime.New(env, "", false, false, 0*time.Second)
- return p.Execute(path, environment.New(), rt)
-func TestPlanStagesNone(t *testing.T) {
- err := runPlan("empty", p, nil)
-func TestPlanStagesSingle(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{"count": count}
- err := runPlan("single", p, tasks)
- assert.Equal(t, 1, count.Count)
-func TestPlanStagesMultiple(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{"count": count}
- err := runPlan("multiple", p, tasks)
- assert.Equal(t, 2, count.Count)
-func TestPlanStagesRunOnFailure(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{
- err := runPlan("run-on-failure", p, tasks)
- assert.Equal(t, 1, count.Count)
-func TestPlanStagesRunOnSuccess(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{
- err := runPlan("run-on-success", p, tasks)
- assert.Equal(t, 0, count.Count)
-func TestPlanStagesRunAlways(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{
- err := runPlan("run-always", p, tasks)
- assert.Equal(t, 1, count.Count)
-func TestPlanStagesDisabled(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{
- err := runPlan("disabled-stage-skipped", p, tasks)
- assert.Equal(t, 1, count.Count)
-func TestPlanStagesConcurrent(t *testing.T) {
- p := unmarshal(t, data)
- count := &tasks.Count{}
- tasks := map[string]runtime.Task{
- err := runPlan("concurrent-stage", p, tasks)
- assert.Equal(t, 2, count.Count)
--- a/runner/cmd.go Thu Dec 23 09:18:29 2021 -0600
+++ b/runner/cmd.go Thu Dec 23 09:31:26 2021 -0600
@@ -15,7 +15,6 @@
"keep.imfreedom.org/grim/convey/environment"
"keep.imfreedom.org/grim/convey/globals"
"keep.imfreedom.org/grim/convey/logging"
- "keep.imfreedom.org/grim/convey/plans"
"keep.imfreedom.org/grim/convey/runtime"
@@ -31,7 +30,7 @@
Plans []string `kong:"arg,help='The names of the plans to run',default='default'"`
-func (c *RunnerCmd) runPlan(name string, cfg *config.Config, plan plans.Plan) error {
+func (c *RunnerCmd) runPlan(name string, cfg *config.Config, plan runtime.Plan) error { configPath, _ := filepath.Split(c.ConfigFile)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/count_task.go Thu Dec 23 09:31:26 2021 -0600
@@ -0,0 +1,49 @@
+// 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/>. + log "github.com/sirupsen/logrus" + "keep.imfreedom.org/grim/convey/environment" +// Count represents a count task. +// Execute runs the count task. +func (c *Count) Execute(name string, logger *log.Entry, env environment.Environment, rt *Runtime) error { +// New creates a new count task. +func (c *Count) New() Task { +// Valid validates the count task. +func (c *Count) Valid() error { +func (c *Count) Deprecated() error { --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/fail.go Thu Dec 23 09:31:26 2021 -0600
@@ -0,0 +1,47 @@
+// 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/>. + log "github.com/sirupsen/logrus" + "keep.imfreedom.org/grim/convey/environment" +// Fail represents a fail task. +// Execute runs the fail task. +func (c *Fail) Execute(name string, logger *log.Entry, env environment.Environment, rt *Runtime) error { + return fmt.Errorf("convey/fail task always fails") +// New creates a new fail task. +func (c *Fail) New() Task { +// Valid validates the fail task. +func (c *Fail) Valid() error { +func (f *Fail) Deprecated() error { --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/plans.go Thu Dec 23 09:31:26 2021 -0600
@@ -0,0 +1,101 @@
+// 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 plans contains the plans structure. + log "github.com/sirupsen/logrus" + "keep.imfreedom.org/grim/convey/environment" + "keep.imfreedom.org/grim/convey/logging" + "keep.imfreedom.org/grim/convey/yaml" + // ErrNoStages is an error that can be returned from Plan.Valid. + ErrNoStages = errors.New("no stages found") +// Plan is the representation of a Plan. + Environment yaml.StringOrSlice `yaml:"environment"` + Stages []Stage `yaml:"stages"` +// Execute runs the plan. +func (p *Plan) Execute(path string, configEnv environment.Environment, rt *Runtime) error { + if err := p.Valid(); err != nil { + planEnv := configEnv.Copy().MergeSlice(p.Environment).Merge(rt.Environment) + p.logger = logging.NewAdapter(path) + // set a flag on whether or not we've failed + for idx, stage := range p.Stages { + absStageName = fmt.Sprintf("%s/%s", path, stage.Name) + absStageName = fmt.Sprintf("%s/%d", path, idx) + stageLogger := logging.NewAdapter(absStageName) + if stage.ShouldRun(planErr) { + stageLogger.Info("stage starting") + err := stage.Execute(absStageName, stageLogger, planEnv, rt) + elapsed := time.Since(start) + p.logger.Debugf("remaining plantime: %s", rt.Timeout) + stageLogger.Error("stage failed") + stageLogger.Infof("stage finished [%s]", elapsed.Round(10*time.Millisecond)) +// Valid validates the plan. +func (p *Plan) Valid() error { + if len(p.Stages) == 0 { --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/plans_stages_test.go Thu Dec 23 09:31:26 2021 -0600
@@ -0,0 +1,189 @@
+// 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/>. + "github.com/stretchr/testify/assert" + "keep.imfreedom.org/grim/convey/environment" +func runPlan(path string, p Plan, tasks map[string]Task) error { + env := environment.New() + rt := New(env, "", false, false, 0*time.Second) + return p.Execute(path, environment.New(), rt) +func TestPlanStagesNone(t *testing.T) { + err := runPlan("empty", p, nil) +func TestPlanStagesSingle(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{"count": count} + err := runPlan("single", p, tasks) + assert.Equal(t, 1, count.Count) +func TestPlanStagesMultiple(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{"count": count} + err := runPlan("multiple", p, tasks) + assert.Equal(t, 2, count.Count) +func TestPlanStagesRunOnFailure(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{ + err := runPlan("run-on-failure", p, tasks) + assert.Equal(t, 1, count.Count) +func TestPlanStagesRunOnSuccess(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{ + err := runPlan("run-on-success", p, tasks) + assert.Equal(t, 0, count.Count) +func TestPlanStagesRunAlways(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{ + err := runPlan("run-always", p, tasks) + assert.Equal(t, 1, count.Count) +func TestPlanStagesDisabled(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{ + err := runPlan("disabled-stage-skipped", p, tasks) + assert.Equal(t, 1, count.Count) +func TestPlanStagesConcurrent(t *testing.T) { + p := unmarshal(t, data) + tasks := map[string]Task{ + err := runPlan("concurrent-stage", p, tasks) + assert.Equal(t, 2, count.Count) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/plans_test.go Thu Dec 23 09:31:26 2021 -0600
@@ -0,0 +1,73 @@
+// 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/>. + "github.com/stretchr/testify/assert" + cYaml "keep.imfreedom.org/grim/convey/yaml" +func unmarshal(t *testing.T, data string) Plan { + err := yaml.Unmarshal([]byte(data), &p) +func TestEnvironmentSlice(t *testing.T) { + p := unmarshal(t, data) + assert.Equal(t, p.Environment, cYaml.StringOrSlice{"foo=bar", "baz"}) +func TestEnvironmentString(t *testing.T) { + data := `environment: foo=bar + p := unmarshal(t, data) + assert.Equal(t, p.Environment, cYaml.StringOrSlice{"foo=bar"}) +func TestStagesRequired(t *testing.T) { + assert.EqualError(t, err, ErrNoStages.Error()) + assert.Len(t, p.Stages, 0) +func TestValid(t *testing.T) { + p := unmarshal(t, data) + assert.Nil(t, p.Valid()) --- a/tasks/README.md Thu Dec 23 09:18:29 2021 -0600
+++ b/tasks/README.md Thu Dec 23 09:31:26 2021 -0600
@@ -51,22 +51,6 @@
-The fail task just automatically fails. It's similar to `convey/noop` in that
-it's mostly used for debugging.
-----
An import task copies files from the host to the workspace. It has one required
--- a/tasks/count.go Thu Dec 23 09:18:29 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-// 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/>.
- log "github.com/sirupsen/logrus"
- "keep.imfreedom.org/grim/convey/environment"
- "keep.imfreedom.org/grim/convey/runtime"
-// Count represents a count task.
-// Execute runs the count task.
-func (c *Count) Execute(name string, logger *log.Entry, env environment.Environment, rt *runtime.Runtime) error {
-// New creates a new count task.
-func (c *Count) New() runtime.Task {
-// Valid validates the count task.
-func (c *Count) Valid() error {
-func (c *Count) Deprecated() error {
--- a/tasks/fail.go Thu Dec 23 09:18:29 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-// 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/>.
- log "github.com/sirupsen/logrus"
- "keep.imfreedom.org/grim/convey/environment"
- "keep.imfreedom.org/grim/convey/runtime"
-// Fail represents a fail task.
-// Execute runs the fail task.
-func (c *Fail) Execute(name string, logger *log.Entry, env environment.Environment, rt *runtime.Runtime) error {
- return fmt.Errorf("convey/fail task always fails")
-// New creates a new fail task.
-func (c *Fail) New() runtime.Task {
-// Valid validates the fail task.
-func (c *Fail) Valid() error {
-func (f *Fail) Deprecated() error {
--- a/tasks/tasks.go Thu Dec 23 09:18:29 2021 -0600
+++ b/tasks/tasks.go Thu Dec 23 09:31:26 2021 -0600
@@ -26,7 +26,6 @@
Tasks = map[string]runtime.Task{
"convey/clean": &Clean{},
"convey/export": &Export{},
- "convey/fail": &Fail{},
"convey/import": &Import{},