Move stages.Stage to the runtime package
--- a/plans/plans.go Thu Dec 23 09:08:12 2021 -0600
+++ b/plans/plans.go Thu Dec 23 09:18:29 2021 -0600
@@ -27,7 +27,6 @@
"keep.imfreedom.org/grim/convey/environment"
"keep.imfreedom.org/grim/convey/logging"
"keep.imfreedom.org/grim/convey/runtime"
- "keep.imfreedom.org/grim/convey/stages"
"keep.imfreedom.org/grim/convey/yaml"
@@ -39,7 +38,7 @@
// Plan is the representation of a Plan.
Environment yaml.StringOrSlice `yaml:"environment"`
- Stages []stages.Stage `yaml:"stages"`
+ Stages []runtime.Stage `yaml:"stages"` --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,167 @@
+// 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 stages contains the stages api. + log "github.com/sirupsen/logrus" + "keep.imfreedom.org/grim/convey/environment" + "keep.imfreedom.org/grim/convey/logging" + "keep.imfreedom.org/grim/convey/yaml" + RunOnFailure = "on-failure" + RunOnSuccess = "on-success" +// Stage is a representation of a stage. + Name string `yaml:"name"` + Run string `yaml:"run"` + Environment yaml.StringOrSlice `yaml:"environment"` + Tasks yaml.StringOrSlice `yaml:"tasks"` + Enabled bool `yaml:"enabled"` + Concurrent bool `yaml:"concurrent"` +// UnmarshalYAML is a custom yaml unmarshaller for stages. +func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error { + raw := rawStage{Enabled: true} + if err := unmarshal(&raw); err != nil { + // validate the run attribute + return fmt.Errorf("Invalid value '%s' for run attribute", s.Run) +// Execute runs the stage. +func (s *Stage) Execute(path string, logger *log.Entry, env environment.Environment, rt *Runtime) error { + stageEnv := env.Copy().Merge(env).MergeSlice(s.Environment) + if s.Concurrent && !rt.ForceSequential { + taskRes := make(chan error) + stageRes := make(chan error) + // process all of the task results + go func(taskRes, stageRes chan error) { + for err := range taskRes { + if err != nil && stageErr == nil { + // now close the stageRes channel + // run all of the tasks in go routines + for _, taskName := range s.Tasks { + go func(path, name string, res chan error) { + res <- s.runTask(path, name, stageEnv, rt) + }(path, taskName, taskRes) + // block until the task wait group is done, then close the taskRes channel + // now return the result from the stageRes channel + for _, taskName := range s.Tasks { + err := s.runTask(path, taskName, stageEnv, rt) +func (s *Stage) runTask(path, name string, stageEnv environment.Environment, rt *Runtime) error { + absTaskName := fmt.Sprintf("%s/%s", path, name) + taskLogger := logging.NewAdapter(fmt.Sprintf("%s/%s", path, name)) + taskLogger.Info("starting") + task, found := rt.Tasks[name] + taskLogger.Error("failed, task not found") + return fmt.Errorf("task %s not found", absTaskName) + err := task.Execute(absTaskName, taskLogger, stageEnv, rt) + taskLogger.Errorf("failed, %s", err) + taskLogger.Info("finished") +// ShouldRun will return True if a stage should be run based on the passed in +// error (from the plan) and whether or not the stage is enabled. +func (s *Stage) ShouldRun(err error) bool { + if s.Run == RunAlways { + return s.Run == RunOnFailure + return s.Run == RunOnSuccess --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages_test.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,78 @@
+// 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" +func TestStageShouldRunOnFailEnabled(t *testing.T) { + stage := Stage{Enabled: true} + err := errors.New("testing") + stage.Run = "on-failure" + assert.True(t, stage.ShouldRun(err)) + assert.True(t, stage.ShouldRun(err)) + stage.Run = "on-success" + assert.False(t, stage.ShouldRun(err)) +func TestStageShouldRunOnFailDisabled(t *testing.T) { + stage := Stage{Enabled: false} + err := errors.New("testing") + stage.Run = "on-failure" + assert.False(t, stage.ShouldRun(err)) + assert.False(t, stage.ShouldRun(err)) + stage.Run = "on-success" + assert.False(t, stage.ShouldRun(err)) +func TestStageShouldRunOnSuccessEnabled(t *testing.T) { + stage := Stage{Enabled: true} + stage.Run = "on-success" + assert.True(t, stage.ShouldRun(nil)) + assert.True(t, stage.ShouldRun(nil)) + stage.Run = "on-failure" + assert.False(t, stage.ShouldRun(nil)) +func TestStageShouldRunOnSuccessDisabled(t *testing.T) { + stage := Stage{Enabled: false} + stage.Run = "on-success" + assert.False(t, stage.ShouldRun(nil)) + assert.False(t, stage.ShouldRun(nil)) + stage.Run = "on-failure" + assert.False(t, stage.ShouldRun(nil)) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/runtime/stages_unmarshal_test.go Thu Dec 23 09:18:29 2021 -0600
@@ -0,0 +1,74 @@
+// 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" +func TestUnmarshalDefaults(t *testing.T) { + // we need a non empty string to get go-yaml to call our UnmarshalYAML + err := yaml.Unmarshal([]byte(data), &stage) + assert.Equal(t, stage.Run, "on-success") +func TestUnmarshalInvalidRun(t *testing.T) { + err := yaml.Unmarshal([]byte(data), &stage) +func TestUnmarshalRunOnSuccess(t *testing.T) { + data := `run: on-success` + err := yaml.Unmarshal([]byte(data), &stage) + assert.Equal(t, stage.Run, "on-success") +func TestUnmarshalRunOnFailure(t *testing.T) { + data := `run: on-failure` + err := yaml.Unmarshal([]byte(data), &stage) + assert.Equal(t, stage.Run, "on-failure") +func TestUnmarshalRunAlways(t *testing.T) { + err := yaml.Unmarshal([]byte(data), &stage) + assert.Equal(t, stage.Run, "always") --- a/stages/stages.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +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 stages contains the stages api.
- 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"
- RunOnFailure = "on-failure"
- RunOnSuccess = "on-success"
-// Stage is a representation of a stage.
- Name string `yaml:"name"`
- Run string `yaml:"run"`
- Environment yaml.StringOrSlice `yaml:"environment"`
- Tasks yaml.StringOrSlice `yaml:"tasks"`
- Enabled bool `yaml:"enabled"`
- Concurrent bool `yaml:"concurrent"`
-// UnmarshalYAML is a custom yaml unmarshaller for stages.
-func (s *Stage) UnmarshalYAML(unmarshal func(interface{}) error) error {
- raw := rawStage{Enabled: true}
- if err := unmarshal(&raw); err != nil {
- // validate the run attribute
- return fmt.Errorf("Invalid value '%s' for run attribute", s.Run)
-// Execute runs the stage.
-func (s *Stage) Execute(path string, logger *log.Entry, env environment.Environment, rt *runtime.Runtime) error {
- stageEnv := env.Copy().Merge(env).MergeSlice(s.Environment)
- if s.Concurrent && !rt.ForceSequential {
- taskRes := make(chan error)
- stageRes := make(chan error)
- // process all of the task results
- go func(taskRes, stageRes chan error) {
- for err := range taskRes {
- if err != nil && stageErr == nil {
- // now close the stageRes channel
- // run all of the tasks in go routines
- for _, taskName := range s.Tasks {
- go func(path, name string, res chan error) {
- res <- s.runTask(path, name, stageEnv, rt)
- }(path, taskName, taskRes)
- // block until the task wait group is done, then close the taskRes channel
- // now return the result from the stageRes channel
- for _, taskName := range s.Tasks {
- err := s.runTask(path, taskName, stageEnv, rt)
-func (s *Stage) runTask(path, name string, stageEnv environment.Environment, rt *runtime.Runtime) error {
- absTaskName := fmt.Sprintf("%s/%s", path, name)
- taskLogger := logging.NewAdapter(fmt.Sprintf("%s/%s", path, name))
- taskLogger.Info("starting")
- task, found := rt.Tasks[name]
- taskLogger.Error("failed, task not found")
- return fmt.Errorf("task %s not found", absTaskName)
- err := task.Execute(absTaskName, taskLogger, stageEnv, rt)
- taskLogger.Errorf("failed, %s", err)
- taskLogger.Info("finished")
-// ShouldRun will return True if a stage should be run based on the passed in
-// error (from the plan) and whether or not the stage is enabled.
-func (s *Stage) ShouldRun(err error) bool {
- if s.Run == RunAlways {
- return s.Run == RunOnFailure
- return s.Run == RunOnSuccess
--- a/stages/stages_test.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +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"
-func TestStageShouldRunOnFailEnabled(t *testing.T) {
- stage := Stage{Enabled: true}
- err := errors.New("testing")
- stage.Run = "on-failure"
- assert.True(t, stage.ShouldRun(err))
- assert.True(t, stage.ShouldRun(err))
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(err))
-func TestStageShouldRunOnFailDisabled(t *testing.T) {
- stage := Stage{Enabled: false}
- err := errors.New("testing")
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(err))
- assert.False(t, stage.ShouldRun(err))
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(err))
-func TestStageShouldRunOnSuccessEnabled(t *testing.T) {
- stage := Stage{Enabled: true}
- stage.Run = "on-success"
- assert.True(t, stage.ShouldRun(nil))
- assert.True(t, stage.ShouldRun(nil))
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(nil))
-func TestStageShouldRunOnSuccessDisabled(t *testing.T) {
- stage := Stage{Enabled: false}
- stage.Run = "on-success"
- assert.False(t, stage.ShouldRun(nil))
- assert.False(t, stage.ShouldRun(nil))
- stage.Run = "on-failure"
- assert.False(t, stage.ShouldRun(nil))
--- a/stages/unmarshal_test.go Thu Dec 23 09:08:12 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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"
-func TestUnmarshalDefaults(t *testing.T) {
- // we need a non empty string to get go-yaml to call our UnmarshalYAML
- err := yaml.Unmarshal([]byte(data), &stage)
- assert.Equal(t, stage.Run, "on-success")
-func TestUnmarshalInvalidRun(t *testing.T) {
- err := yaml.Unmarshal([]byte(data), &stage)
-func TestUnmarshalRunOnSuccess(t *testing.T) {
- data := `run: on-success`
- err := yaml.Unmarshal([]byte(data), &stage)
- assert.Equal(t, stage.Run, "on-success")
-func TestUnmarshalRunOnFailure(t *testing.T) {
- data := `run: on-failure`
- err := yaml.Unmarshal([]byte(data), &stage)
- assert.Equal(t, stage.Run, "on-failure")
-func TestUnmarshalRunAlways(t *testing.T) {
- err := yaml.Unmarshal([]byte(data), &stage)
- assert.Equal(t, stage.Run, "always")