From 96de90b36408f7af977d7d575fba1bcd85880131 Mon Sep 17 00:00:00 2001 From: Gilles Dubuc Date: Sun, 20 May 2018 11:19:51 +0200 Subject: Add support for Builder arbitrary build commands Reviewers: thcipriani, dduvall, #release-engineering-team Reviewed By: dduvall, #release-engineering-team Tags: #release-engineering-team Differential Revision: https://phabricator.wikimedia.org/D1054 --- blubber.example.yaml | 1 + config/builder.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ config/builder_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ config/common.go | 20 +++++++++++--------- 4 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 config/builder.go create mode 100644 config/builder_test.go diff --git a/blubber.example.yaml b/blubber.example.yaml index e4fe3c9..80eddc3 100644 --- a/blubber.example.yaml +++ b/blubber.example.yaml @@ -18,6 +18,7 @@ variants: dependencies: true python: requirements: [requirements.txt] + builder: [make, -f, Makefile] development: includes: [build] diff --git a/config/builder.go b/config/builder.go new file mode 100644 index 0000000..112f181 --- /dev/null +++ b/config/builder.go @@ -0,0 +1,47 @@ +package config + +import ( + "phabricator.wikimedia.org/source/blubber/build" +) + +// BuilderConfig contains configuration for the definition of an arbitrary +// build command. +// +type BuilderConfig struct { + Builder []string `yaml:"builder"` +} + +// Merge takes another BuilderConfig and merges its fields into this one's, +// overwriting the builder command. +// +func (bc *BuilderConfig) Merge(bc2 BuilderConfig) { + if len(bc2.Builder) > 0 { + bc.Builder = bc2.Builder + } +} + +// InstructionsForPhase injects instructions into the build related to +// builder commands. +// +// PhasePostInstall +// +// Runs build command provided for the builder +// +func (bc BuilderConfig) InstructionsForPhase(phase build.Phase) []build.Instruction { + switch phase { + case build.PhasePostInstall: + if len(bc.Builder) == 0 { + return []build.Instruction{} + } + + run := build.Run{Command: bc.Builder[0]} + + if len(bc.Builder) > 1 { + run.Arguments = bc.Builder[1:] + } + + return []build.Instruction{run} + } + + return []build.Instruction{} +} diff --git a/config/builder_test.go b/config/builder_test.go new file mode 100644 index 0000000..dbc95d9 --- /dev/null +++ b/config/builder_test.go @@ -0,0 +1,43 @@ +package config_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "phabricator.wikimedia.org/source/blubber/build" + "phabricator.wikimedia.org/source/blubber/config" +) + +func TestBuilderConfigYAML(t *testing.T) { + cfg, err := config.ReadConfig([]byte(`--- + version: v1 + base: foo + variants: + build: + builder: [make, -f, Makefile]`)) + + if assert.NoError(t, err) { + variant, err := config.ExpandVariant(cfg, "build") + + assert.Equal(t, []string{"make", "-f", "Makefile"}, variant.Builder) + + assert.Nil(t, err) + } +} + +func TestBuilderConfigInstructions(t *testing.T) { + cfg := config.BuilderConfig{Builder: []string{"make", "-f", "Makefile"}} + + t.Run("PhasePostInstall", func(t *testing.T) { + assert.Equal(t, + []build.Instruction{ + build.Run{ + "make", + []string{"-f", "Makefile"}, + }, + }, + cfg.InstructionsForPhase(build.PhasePostInstall), + ) + }) +} diff --git a/config/common.go b/config/common.go index 4cc300d..96fb2b0 100644 --- a/config/common.go +++ b/config/common.go @@ -8,14 +8,15 @@ import ( // and each configured variant. // type CommonConfig struct { - Base string `yaml:"base" validate:"omitempty,baseimage"` // name/path to base image - Apt AptConfig `yaml:"apt"` // APT related - Node NodeConfig `yaml:"node"` // Node related - Python PythonConfig `yaml:"python"` // Python related - Lives LivesConfig `yaml:"lives"` // application owner/dir - Runs RunsConfig `yaml:"runs"` // runtime environment - SharedVolume Flag `yaml:"sharedvolume"` // use volume for app - EntryPoint []string `yaml:"entrypoint"` // entry-point executable + Base string `yaml:"base" validate:"omitempty,baseimage"` // name/path to base image + Apt AptConfig `yaml:"apt"` // APT related + Node NodeConfig `yaml:"node"` // Node related + Python PythonConfig `yaml:"python"` // Python related + BuilderConfig `yaml:",inline"` // Builder related + Lives LivesConfig `yaml:"lives"` // application owner/dir + Runs RunsConfig `yaml:"runs"` // runtime environment + SharedVolume Flag `yaml:"sharedvolume"` // use volume for app + EntryPoint []string `yaml:"entrypoint"` // entry-point executable } // Merge takes another CommonConfig and merges its fields this one's. @@ -28,6 +29,7 @@ func (cc *CommonConfig) Merge(cc2 CommonConfig) { cc.Apt.Merge(cc2.Apt) cc.Node.Merge(cc2.Node) cc.Python.Merge(cc2.Python) + cc.BuilderConfig.Merge(cc2.BuilderConfig) cc.Lives.Merge(cc2.Lives) cc.Runs.Merge(cc2.Runs) cc.SharedVolume.Merge(cc2.SharedVolume) @@ -42,7 +44,7 @@ func (cc *CommonConfig) Merge(cc2 CommonConfig) { // injected. // func (cc *CommonConfig) PhaseCompileableConfig() []build.PhaseCompileable { - return []build.PhaseCompileable{cc.Apt, cc.Node, cc.Python, cc.Lives, cc.Runs} + return []build.PhaseCompileable{cc.Apt, cc.Node, cc.Python, cc.BuilderConfig, cc.Lives, cc.Runs} } // InstructionsForPhase injects instructions into the given build phase for -- cgit v1.2.1