--- a/loaders/convey/convey.go Thu Sep 14 19:08:14 2017 -0500
+++ b/loaders/convey/convey.go Thu Sep 14 19:31:03 2017 -0500
@@ -51,6 +51,7 @@
+ fileLoader func(string, *Loader) (*cConfig.Config, error) func (c *Loader) Load(path, base string, data []byte) (*cConfig.Config, error) {
@@ -68,13 +69,13 @@
var baseConfig *cConfig.Config
- baseConfig, err = cConfig.LoadFile(cfg.Extends, c)
+ baseConfig, err = c.loadFile(cfg.Extends) // 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 {
+ if err != nil && err != ErrNoPlans && err != ErrNoTasks { @@ -152,6 +153,14 @@
+func (c *Loader) loadFile(path string) (*cConfig.Config, error) { + if c.fileLoader == nil { + return cConfig.LoadFile(path, c) + return c.fileLoader(path, c) func (c *Loader) LoadOverride(path, base string, data []byte, config *cConfig.Config) {
var overrideData override
--- a/loaders/convey/convey_test.go Thu Sep 14 19:08:14 2017 -0500
+++ b/loaders/convey/convey_test.go Thu Sep 14 19:31:03 2017 -0500
@@ -37,6 +37,7 @@
s.RegisterPlugin(junit.NewPlugin())
s.AddSuite(&conveySuite{})
+ s.AddSuite(&extendsSuite{}) s.AddSuite(&defaultPlanSuite{})
s.AddSuite(&environmentSuite{})
--- a/loaders/convey/environment_test.go Thu Sep 14 19:08:14 2017 -0500
+++ b/loaders/convey/environment_test.go Thu Sep 14 19:31:03 2017 -0500
@@ -48,7 +48,7 @@
cfg, err := loader.Load(".", ".", []byte(data))
- Expect(cfg.Environment).To(Equal([]string{"foo=bar", "baz"}))
+ Expect(cfg.Environment).To(ConsistOf([]string{"foo=bar", "baz"})) func (e *environmentSuite) TestEnvironmentUnmarshalGlobalString(t sweet.T) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/loaders/convey/extends_test.go Thu Sep 14 19:31:03 2017 -0500
@@ -0,0 +1,170 @@
+ * Copyright 2016-2017 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/>. + "bitbucket.org/rw_grim/convey/docker" + "github.com/aphistic/sweet" + . "github.com/onsi/gomega" + cConfig "bitbucket.org/rw_grim/convey/config" +// This test suite tests +type extendsSuite struct{} +func (d *extendsSuite) TestNoClash(t sweet.T) { + - tasks: [foo, bar, baz] + fileLoader: func(name string, c *Loader) (*cConfig.Config, error) { + return c.Load(".", name, []byte(baseData)) + cfg, err := loader.Load(".", ".", []byte(extendedData)) + Expect(err).To(BeNil()) + Expect(cfg.Environment).To(ConsistOf([]string{"x=1", "y=2", "z=3", "w=4"})) + Expect(cfg.Tasks).To(HaveLen(4)) + Expect(cfg.Tasks).To(HaveKey("foo")) + Expect(cfg.Tasks).To(HaveKey("bar")) + Expect(cfg.Tasks).To(HaveKey("baz")) + Expect(cfg.Tasks).To(HaveKey("bonk")) + Expect(cfg.Plans).To(HaveLen(2)) + Expect(cfg.Plans).To(HaveKey("plan1")) + Expect(cfg.Plans).To(HaveKey("plan2")) +func (d *extendsSuite) TestExtendsAndOverwrite(t sweet.T) { + - tasks: [foo, bar, baz] + fileLoader: func(name string, c *Loader) (*cConfig.Config, error) { + return c.Load(".", name, []byte(baseData)) + cfg, err := loader.Load(".", ".", []byte(extendedData)) + Expect(err).To(BeNil()) + Expect(cfg.Environment).To(ConsistOf([]string{"x=1", "y=2", "z=4"})) + Expect(cfg.Tasks).To(HaveLen(3)) + Expect(cfg.Tasks).To(HaveKey("foo")) + Expect(cfg.Tasks).To(HaveKey("bar")) + Expect(cfg.Tasks).To(HaveKey("baz")) + Expect(cfg.Plans).To(HaveLen(1)) + Expect(cfg.Plans).To(HaveKey("plan1")) + Expect(cfg.Tasks["baz"].(*docker.Run).Image).To(Equal("imaginary4")) + Expect(cfg.Plans["plan1"].Stages[0].Tasks).To(BeEquivalentTo([]string{"foo", "baz"})) +func (d *extendsSuite) ExtendDefault(t sweet.T) { + fileLoader: func(name string, c *Loader) (*cConfig.Config, error) { + return c.Load(".", name, []byte(baseData)) + _, err := loader.Load(".", ".", []byte(extendedData)) + Expect(err).To(BeNil()) + Expect(loader.defaultPlan).To(Equal("plan2"))