--- a/loaders/convey/convey.go Thu Sep 14 18:32:15 2017 -0500
+++ b/loaders/convey/convey.go Thu Sep 14 19:08:14 2017 -0500
@@ -26,6 +26,7 @@
"bitbucket.org/rw_grim/convey/environment"
"bitbucket.org/rw_grim/convey/plans"
"bitbucket.org/rw_grim/convey/state"
+ "bitbucket.org/rw_grim/convey/tasks" cYaml "bitbucket.org/rw_grim/convey/yaml"
@@ -35,6 +36,7 @@
+ Extends string `yaml:"extends"` Tasks map[string]yaml.MapSlice `yaml:"tasks"`
Plans map[string]plans.Plan `yaml:"plans"`
MetaPlans map[string]plans.MetaPlan `yaml:"meta-plans"`
@@ -59,12 +61,29 @@
- if len(cfg.Tasks) == 0 {
+ // see if we're extending something - partially load a base + // config object if so that we'll modify; otherwise use an + // empty base config object that we'll set in a similar way + var baseConfig *cConfig.Config + baseConfig, err = cConfig.LoadFile(cfg.Extends, c) - if len(cfg.Plans) == 0 {
+ // We can safely ignore no plans and no tasks errors here + // as we're ensured to also get a valid base config back. + // This is a bit of a strange idiom, but is still used in + // places like io.Reader (return non-zero n on error). + if err != nil && err != ErrNoPlans || err != ErrNoTasks { + baseConfig = &cConfig.Config{ + Tasks: map[string]tasks.Task{}, + Plans: map[string]plans.Plan{}, + MetaPlans: map[string]plans.MetaPlan{}, + SSHIdentities: []string{}, // turn the raw tasks into real tasks
@@ -76,7 +95,7 @@
// iterate through each plan and do any cleanup we need to
for _, plan := range cfg.Plans {
// set stage names for any that are missing them
- for idx, _ := range plan.Stages {
+ for idx := range plan.Stages { if plan.Stages[idx].Name == "" {
plan.Stages[idx].Name = fmt.Sprintf("stage-%d", idx)
@@ -86,16 +105,51 @@
// store the default plan in the loader
c.defaultPlan = cfg.Options.DefaultPlan
- // create the real config
- realConfig := &cConfig.Config{
- Environment: cfg.Environment,
- MetaPlans: cfg.MetaPlans,
- SSHIdentities: cfg.Options.SSHIdentities,
+ // tasks, plans, and metaplans are all name => * maps, and + // if we're extending something we want to inherit all of these + // EXCEPT for things that we are explicitly overriding by using + // the same name. Do a shallow merge here + for name, task := range realTasks { + baseConfig.Tasks[name] = task + for name, plan := range cfg.Plans { + baseConfig.Plans[name] = plan + for name, metaPlan := range cfg.MetaPlans { + baseConfig.MetaPlans[name] = metaPlan
+ baseConfig.Environment = environment.Merge(baseConfig.Environment, cfg.Environment) + // Check if the default plan is being overridden + if cfg.Options.DefaultPlan != "" { + c.defaultPlan = cfg.Options.DefaultPlan + // don't clobber ssh-identities with an empty list + if len(cfg.Options.SSHIdentities) > 0 { + baseConfig.SSHIdentities = cfg.Options.SSHIdentities + // Return the base config at this point, but maybe possibly return an + // error that we're missing something in order to proceed. This gets + // kind of weird: if we're calling Load recursively through LoadFile, + // as is the case with extending a config file, we're going to ignore + // these errors but need the actual config (we may define tasks and + // plans in an extending config). + if len(baseConfig.Tasks) == 0 { + return baseConfig, ErrNoTasks + if len(baseConfig.Plans) == 0 { + return baseConfig, ErrNoPlans func (c *Loader) LoadOverride(path, base string, data []byte, config *cConfig.Config) {
--- a/loaders/convey/convey_test.go Thu Sep 14 18:32:15 2017 -0500
+++ b/loaders/convey/convey_test.go Thu Sep 14 19:08:14 2017 -0500
@@ -75,9 +75,8 @@
- cfg, err := l.Load(".", ".", []byte(data))
+ _, err := l.Load(".", ".", []byte(data)) Expect(err).To(MatchError(ErrNoTasks))
- Expect(cfg).To(BeNil())
func (s *conveySuite) TestPlansRequired(t sweet.T) {
@@ -88,7 +87,6 @@
- cfg, err := l.Load(".", ".", []byte(data))
+ _, err := l.Load(".", ".", []byte(data)) Expect(err).To(MatchError(ErrNoPlans))
- Expect(cfg).To(BeNil())
--- a/loaders/convey/environment_test.go Thu Sep 14 18:32:15 2017 -0500
+++ b/loaders/convey/environment_test.go Thu Sep 14 19:08:14 2017 -0500
@@ -67,7 +67,7 @@
cfg, err := loader.Load(".", ".", []byte(baseData))
- Expect(cfg.Environment).To(BeNil())
+ Expect(cfg.Environment).To(BeEmpty()) @@ -84,7 +84,7 @@
cfg, err := loader.Load(".", ".", []byte(baseData))
- Expect(cfg.Environment).To(BeNil())
+ Expect(cfg.Environment).To(BeEmpty())