Rename inject task to environment.
--- a/REFERENCE.md Wed Oct 11 20:48:50 2017 -0500
+++ b/REFERENCE.md Fri Oct 13 12:04:21 2017 -0500
@@ -50,9 +50,9 @@
This example shows how to expand an environment variable into a list in the context of a extended task.
+## environment-from-file.yml -This example shows how to inject variables from a file in the build container into the plan.
+This example shows how to inject variables into the environment from a file in the build container. @@ -176,14 +176,14 @@
-An inject task will read a variable with environment variables and make them accessible to your plans.
+An environment task will read a file with environment variables and make them accessible to your plans. A file is expected to have lines of the form `variable=value`. Empty lines are ignored. Files are read
from the docker volume, so files generated by the plan do not need to be exported in order to be a target
-of an inject task. From the other direction, it is necessary to import files on the host if they are to be
+of an environment task. From the other direction, it is necessary to import files on the host if they are +to be read by an environment task. @@ -193,17 +193,16 @@
| files | | | A list of files that should be read. |
| prefix | | | A prefix to add to each variable read from a file |
-At least one file must be supplied by either the `file` or `files` attributes. If both are
-supplied, `file` is inserted to the front of `files`. If the files being read are a result of
-environment variable expansion, the order that the files are read are not guaranteed to be
-stable (or in the order supplied). Be cautious of this if the environment files have define
+At least one file must be supplied by either the `from-file` or `fromfiles` attributes. If both are supplied, +`from-file` is inserted to the front of `from-files`. If the files being read are a result of environment variable +expansion, the order that the files are read are not guaranteed to be stable (or in the order supplied). Be cautious +of this if the environment files have define overlapping variables.
--- a/docker/docker.go Wed Oct 11 20:48:50 2017 -0500
+++ b/docker/docker.go Fri Oct 13 12:04:21 2017 -0500
@@ -25,17 +25,17 @@
Tasks = map[string]tasks.Task{
+ "environment": &Environment{}, dockerTemplate = `docker {{if .DockerConfig}}--config {{.DockerConfig}} {{end}}`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docker/environment.go Fri Oct 13 12:04:21 2017 -0500
@@ -0,0 +1,141 @@
+ * 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/>. + "github.com/aphistic/gomol" + "bitbucket.org/rw_grim/convey/environment" + "bitbucket.org/rw_grim/convey/state" + "bitbucket.org/rw_grim/convey/tasks" + "bitbucket.org/rw_grim/convey/yaml" +type Environment struct { + File string `yaml:"from-file"` + Files yaml.StringOrSlice `yaml:"from-files"` + Prefix string `yaml:"prefix"` +func (e *Environment) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error { + fullEnv := environment.Merge(env, st.GetEnv()) + prefix, err := environment.Mapper(e.Prefix, fullEnv) + files, err := st.MapSlice(e.Files, fullEnv) + // Create a temp directory we can export files from the current + // container into. We can't read directly from the volume, and + // we don't want to require reading only environment files on + tmpDir, err := ioutil.TempDir("", "convey-environment-") + defer os.RemoveAll(tmpDir) + for _, file := range files { + // Export the file into the temp directory and maintain the + // structure of the file (for ease of error messages, so we + // get the file a/b/c/env instead of env). + dest := filepath.Clean(filepath.Join(tmpDir, file)) + if err = exportFile(name, st.Workspace.Name(), file, dest, st); err != nil { + // Process the entries of the file and apply them to the + // state's base environment immediately. + entries, err := processFile(dest, file, prefix) +func processFile(path, name, prefix string) ([]string, error) { + data, err := ioutil.ReadFile(path) + return nil, fmt.Errorf("failed to read environment file '%s'", name) + for _, line := range strings.Split(string(data), "\n") { + if len(strings.TrimSpace(line)) == 0 { + // Each non-empty line requires the form key=val. Split the + // key and the val, then uppercase the key and add the prefix. + // We don't care what form val takes, it will be treated as a + // string (does not need to be quoted). + parts := strings.SplitN(line, "=", 2) + return nil, fmt.Errorf("malformed entry in environments file '%s'", line) + key = strings.TrimSpace(parts[0]) + val = strings.TrimSpace(parts[1]) + return nil, fmt.Errorf("malformed entry in environments file '%s'", line) + entries = append(entries, fmt.Sprintf("%s%s=%s", prefix, strings.ToUpper(key), val)) +func (e *Environment) New() tasks.Task { +func (e *Environment) Valid() error { + e.Files = append([]string{e.File}, e.Files...) + return errNoFilesEnvironment --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docker/environment_test.go Fri Oct 13 12:04:21 2017 -0500
@@ -0,0 +1,58 @@
+ * 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/>. + "github.com/aphistic/sweet" + "github.com/go-yaml/yaml" + . "github.com/onsi/gomega" + cYaml "bitbucket.org/rw_grim/convey/yaml" +func (s *dockerSuite) TestEnvironment(t sweet.T) { + i := &Environment{Files: cYaml.StringOrSlice{"foo"}} + Expect(i.Valid()).To(BeNil()) +func (s *dockerSuite) TestEnvironmentFilesRequired(t sweet.T) { + Expect(i.Valid()).To(MatchError(errNoFilesEnvironment)) +func (s *dockerSuite) TestEnvironmentUnmarshalString(t sweet.T) { + data := `from-files: filename` + err := yaml.Unmarshal([]byte(data), &imp) + Expect(err).To(BeNil()) + Expect(imp.Files).To(Equal(cYaml.StringOrSlice{"filename"})) +func (s *dockerSuite) TestEnvironmentUnmarshalStringSlice(t sweet.T) { + err := yaml.Unmarshal([]byte(data), &imp) + Expect(err).To(BeNil()) + Expect(imp.Files).To(Equal(cYaml.StringOrSlice{"filename1", "filename2"})) --- a/docker/export_test.go Wed Oct 11 20:48:50 2017 -0500
+++ b/docker/export_test.go Fri Oct 13 12:04:21 2017 -0500
@@ -18,50 +18,19 @@
- . "github.com/onsi/gomega"
- "github.com/aphistic/sweet"
- "github.com/go-yaml/yaml"
- cYaml "bitbucket.org/rw_grim/convey/yaml"
-func (s *dockerSuite) TestExport(t sweet.T) {
- e := &Export{Files: cYaml.StringOrSlice{"foo"}}
- Expect(e.Valid()).To(BeNil())
-func (s *dockerSuite) TestExportFilesRequired(t sweet.T) {
- Expect(e.Valid()).To(MatchError(errNoFiles))
-func (s *dockerSuite) TestExportFilesDoesNotAllowWildcardWithDestination(t sweet.T) {
- Files: cYaml.StringOrSlice{"*:/foo"},
- Expect(e.Valid()).To(MatchError(errWildcardWithDestination))
-func (s *dockerSuite) TestExportUnmarshalString(t sweet.T) {
- data := `files: filename`
- err := yaml.Unmarshal([]byte(data), &exp)
- Expect(err).To(BeNil())
- Expect(exp.Files).To(Equal(cYaml.StringOrSlice{"filename"}))
-func (s *dockerSuite) TestExportUnmarshalStringSlice(t sweet.T) {
- err := yaml.Unmarshal([]byte(data), &exp)
- Expect(err).To(BeNil())
- Expect(exp.Files).To(Equal(cYaml.StringOrSlice{"filename1", "filename2"}))
+ errNoDockerFile = errors.New("no dockerfile specified") + errNoTag = errors.New("no tag specified") + errWildcardWithDestination = errors.New("file list contains a wildcard with a destination") + errNoFiles = errors.New("no files specified") + errNoServer = errors.New("no server specified") + errNoUsername = errors.New("no username specified") + errNoImage = errors.New("no image specified") + errNoImages = errors.New("no images specified") + errNoSourceTag = errors.New("no source tag specified") + errNoDestinationTags = errors.New("no destination tags specified") + errNoFilesEnvironment = errors.New("no environment files specified") --- a/docker/inject.go Wed Oct 11 20:48:50 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +0,0 @@
- * 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/>.
- "github.com/aphistic/gomol"
- "bitbucket.org/rw_grim/convey/environment"
- "bitbucket.org/rw_grim/convey/state"
- "bitbucket.org/rw_grim/convey/tasks"
- "bitbucket.org/rw_grim/convey/yaml"
- File string `yaml:"file"`
- Files yaml.StringOrSlice `yaml:"files"`
- Prefix string `yaml:"prefix"`
-func (i *Inject) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
- fullEnv := environment.Merge(env, st.GetEnv())
- prefix, err := environment.Mapper(i.Prefix, fullEnv)
- files, err := st.MapSlice(i.Files, fullEnv)
- // Create a temp directory we can export files from the current
- // container into. We can't read directly from the volume, and
- // we don't want to require reading only environment files on
- tmpDir, err := ioutil.TempDir("", "convey-inject-")
- defer os.RemoveAll(tmpDir)
- for _, file := range files {
- // Export the file into the temp directory and maintain the
- // structure of the file (for ease of error messages, so we
- // get the file a/b/c/env instead of env).
- dest := filepath.Clean(filepath.Join(tmpDir, file))
- if err = exportFile(name, st.Workspace.Name(), file, dest, st); err != nil {
- // Process the entries of the file and apply them to the
- // state's base environment immediately.
- entries, err := processFile(dest, file, prefix)
-func processFile(path, name, prefix string) ([]string, error) {
- data, err := ioutil.ReadFile(path)
- return nil, fmt.Errorf("failed to read environment file '%s'", name)
- for _, line := range strings.Split(string(data), "\n") {
- if len(strings.TrimSpace(line)) == 0 {
- // Each non-empty line requires the form key=val. Split the
- // key and the val, then uppercase the key and add the prefix.
- // We don't care what form val takes, it will be treated as a
- // string (does not need to be quoted).
- parts := strings.SplitN(line, "=", 2)
- return nil, fmt.Errorf("malformed entry in environments file '%s'", line)
- key = strings.TrimSpace(parts[0])
- val = strings.TrimSpace(parts[1])
- return nil, fmt.Errorf("malformed entry in environments file '%s'", line)
- entries = append(entries, fmt.Sprintf("%s%s=%s", prefix, strings.ToUpper(key), val))
-func (i *Inject) New() tasks.Task {
-func (i *Inject) Valid() error {
- i.Files = append([]string{i.File}, i.Files...)
- return errNoFilesInject
--- a/docker/inject_test.go Wed Oct 11 20:48:50 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
- * 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/>.
- "github.com/aphistic/sweet"
- "github.com/go-yaml/yaml"
- . "github.com/onsi/gomega"
- cYaml "bitbucket.org/rw_grim/convey/yaml"
-func (s *dockerSuite) TestInject(t sweet.T) {
- i := &Inject{Files: cYaml.StringOrSlice{"foo"}}
- Expect(i.Valid()).To(BeNil())
-func (s *dockerSuite) TestInjectFilesRequired(t sweet.T) {
- Expect(i.Valid()).To(MatchError(errNoFilesInject))
-func (s *dockerSuite) TestInjectUnmarshalString(t sweet.T) {
- data := `files: filename`
- err := yaml.Unmarshal([]byte(data), &imp)
- Expect(err).To(BeNil())
- Expect(imp.Files).To(Equal(cYaml.StringOrSlice{"filename"}))
-func (s *dockerSuite) TestInjectUnmarshalStringSlice(t sweet.T) {
- err := yaml.Unmarshal([]byte(data), &imp)
- Expect(err).To(BeNil())
- Expect(imp.Files).To(Equal(cYaml.StringOrSlice{"filename1", "filename2"}))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/environment-from-file.yml Fri Oct 13 12:04:21 2017 -0500
@@ -0,0 +1,56 @@
+# This plan shows how the inject plan can add additional +# environment variables accessible to your tasks during +# runtime. Running this with `-e X_FOO=4`, the output +# will be (in two parts): +# Notice that before the inject task, only X_FOO and X_BAR +# were set by the command line argument and the global env +# block, respectively. Afterwards, X_FOO's value did not +# change (as command line parameters take have precedence), +# X_BAR is overwritten, and X_BAZ is newly added. + image: gliderlabs/alpine:edge + image: gliderlabs/alpine:edge + - echo "X_FOO=${X_FOO}" + - echo "X_BAR=${X_BAR}" + - echo "X_BAZ=${X_BAZ}" --- a/examples/inject.yml Wed Oct 11 20:48:50 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-# This plan shows how the inject plan can add additional
-# environment variables accessible to your tasks during
-# runtime. Running this with `-e X_FOO=4`, the output
-# will be (in two parts):
-# Notice that before the inject task, only X_FOO and X_BAR
-# were set by the command line argument and the global env
-# block, respectively. Afterwards, X_FOO's value did not
-# change (as command line parameters take have precedence),
-# X_BAR is overwritten, and X_BAZ is newly added.
- image: gliderlabs/alpine:edge
- image: gliderlabs/alpine:edge
- - echo "X_FOO=${X_FOO}"
- - echo "X_BAR=${X_BAR}"
- - echo "X_BAZ=${X_BAZ}"