diff --git a/command/build_test.go b/command/build_test.go index 12f9709d2..2a2ba1734 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -28,7 +28,7 @@ func TestBuildOnlyFileCommaFlags(t *testing.T) { } for _, f := range []string{"chocolate.txt", "vanilla.txt", - "apple.txt", "peach.txt", "pear.txt"} { + "apple.txt", "peach.txt", "pear.txt", "unnamed.txt"} { if !fileExists(f) { t.Errorf("Expected to find %s", f) } @@ -62,7 +62,8 @@ func TestBuildStdin(t *testing.T) { fatalCommand(t, c.Meta) } - for _, f := range []string{"vanilla.txt", "cherry.txt", "chocolate.txt"} { + for _, f := range []string{"vanilla.txt", "cherry.txt", "chocolate.txt", + "unnamed.txt"} { if !fileExists(f) { t.Errorf("Expected to find %s", f) } @@ -89,13 +90,37 @@ func TestBuildOnlyFileMultipleFlags(t *testing.T) { fatalCommand(t, c.Meta) } - for _, f := range []string{"vanilla.txt"} { + for _, f := range []string{"vanilla.txt", "tomato.txt"} { if fileExists(f) { t.Errorf("Expected NOT to find %s", f) } } for _, f := range []string{"chocolate.txt", "cherry.txt", - "apple.txt", "peach.txt", "pear.txt"} { + "apple.txt", "peach.txt", "pear.txt", "unnamed.txt"} { + if !fileExists(f) { + t.Errorf("Expected to find %s", f) + } + } +} + +func TestBuildEverything(t *testing.T) { + c := &BuildCommand{ + Meta: testMetaFile(t), + } + + args := []string{ + `-except=`, + filepath.Join(testFixture("build-only"), "template.json"), + } + + defer cleanup() + + if code := c.Run(args); code != 0 { + fatalCommand(t, c.Meta) + } + + for _, f := range []string{"chocolate.txt", "vanilla.txt", "tomato.txt", + "apple.txt", "cherry.txt", "pear.txt", "peach.txt", "unnamed.txt"} { if !fileExists(f) { t.Errorf("Expected to find %s", f) } @@ -118,7 +143,8 @@ func TestBuildExceptFileCommaFlags(t *testing.T) { fatalCommand(t, c.Meta) } - for _, f := range []string{"chocolate.txt", "vanilla.txt", "tomato.txt"} { + for _, f := range []string{"chocolate.txt", "vanilla.txt", "tomato.txt", + "unnamed.txt"} { if fileExists(f) { t.Errorf("Expected NOT to find %s", f) } @@ -174,4 +200,5 @@ func cleanup() { os.RemoveAll("peach.txt") os.RemoveAll("pear.txt") os.RemoveAll("tomato.txt") + os.RemoveAll("unnamed.txt") } diff --git a/command/test-fixtures/build-only/template.json b/command/test-fixtures/build-only/template.json index 9ca20adca..01e6bfd13 100644 --- a/command/test-fixtures/build-only/template.json +++ b/command/test-fixtures/build-only/template.json @@ -48,6 +48,15 @@ "type": "shell-local", "inline": [ "touch tomato.txt" ] } + ], + [ + { + "only": [ + "chocolate" + ], + "type": "shell-local", + "inline": [ "touch unnamed.txt" ] + } ] ] } \ No newline at end of file diff --git a/packer/core.go b/packer/core.go index a059f90c9..d88e21e5c 100644 --- a/packer/core.go +++ b/packer/core.go @@ -186,7 +186,7 @@ func (c *Core) Build(n string) (Build, error) { // -except skips post-processor & build foundExcept := false for _, except := range c.except { - if except == rawP.Name { + if except != "" && except == rawP.Name { foundExcept = true } } diff --git a/template/parse.go b/template/parse.go index 9f37929a3..de54f091c 100644 --- a/template/parse.go +++ b/template/parse.go @@ -144,6 +144,11 @@ func (r *rawTemplate) Template() (*Template, error) { continue } + // The name defaults to the type if it isn't set + if pp.Name == "" { + pp.Name = pp.Type + } + // Set the configuration delete(c, "except") delete(c, "only") diff --git a/template/parse_test.go b/template/parse_test.go index 8881783f6..7ba17b2a7 100644 --- a/template/parse_test.go +++ b/template/parse_test.go @@ -4,10 +4,11 @@ package template import ( "path/filepath" - "reflect" "strings" "testing" "time" + + "github.com/google/go-cmp/cmp" ) func TestParse(t *testing.T) { @@ -151,6 +152,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", Config: map[string]interface{}{ "foo": "bar", @@ -168,6 +170,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", KeepInputArtifact: true, }, @@ -183,6 +186,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", OnlyExcept: OnlyExcept{ Only: []string{"bar"}, @@ -200,6 +204,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", OnlyExcept: OnlyExcept{ Except: []string{"bar"}, @@ -217,6 +222,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", }, }, @@ -231,6 +237,7 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", }, }, @@ -245,11 +252,13 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", }, }, { { + Name: "bar", Type: "bar", }, }, @@ -264,9 +273,11 @@ func TestParse(t *testing.T) { PostProcessors: [][]*PostProcessor{ { { + Name: "foo", Type: "foo", }, { + Name: "bar", Type: "bar", }, }, @@ -321,7 +332,7 @@ func TestParse(t *testing.T) { }, } - for _, tc := range cases { + for i, tc := range cases { path, _ := filepath.Abs(fixtureDir(tc.File)) tpl, err := ParseFile(fixtureDir(tc.File)) if (err != nil) != tc.Err { @@ -334,8 +345,8 @@ func TestParse(t *testing.T) { if tpl != nil { tpl.RawContents = nil } - if !reflect.DeepEqual(tpl, tc.Result) { - t.Fatalf("bad: %s\n\n%#v\n\n%#v", tc.File, tpl, tc.Result) + if diff := cmp.Diff(tpl, tc.Result); diff != "" { + t.Fatalf("[%d]bad: %s\n%v", i, tc.File, diff) } } } diff --git a/website/source/docs/commands/build.html.md b/website/source/docs/commands/build.html.md index 61ee8c3a9..7e559b974 100644 --- a/website/source/docs/commands/build.html.md +++ b/website/source/docs/commands/build.html.md @@ -31,7 +31,8 @@ artifacts that are created will be outputted at the end of the build. default are their type, unless a specific `name` attribute is specified within the configuration. Any post-processor following a skipped post-processor will not run. Because post-processors can be nested in - arrays a differ post-processor chain can still run. + arrays a different post-processor chain can still run. A post-processor + with an empty name will be ignored. - `-force` - Forces a builder to run when artifacts from a previous build prevent a build from running. The exact behavior of a forced build is left diff --git a/website/source/docs/commands/validate.html.md b/website/source/docs/commands/validate.html.md index 6f1a54c82..ead5a4fa9 100644 --- a/website/source/docs/commands/validate.html.md +++ b/website/source/docs/commands/validate.html.md @@ -33,10 +33,11 @@ Errors validating build 'vmware'. 1 error(s) occurred: - `-syntax-only` - Only the syntax of the template is checked. The configuration is not validated. -- `-except=foo,bar,baz` - Builds all the builds except those with the given - comma-separated names. Build names by default are the names of their - builders, unless a specific `name` attribute is specified within the - configuration. +- `-except=foo,bar,baz` - Builds all the builds and post-processors except + those with the given comma-separated names. Build and post-processor names + by default are the names of their builders, unless a specific `name` + attribute is specified within the configuration. A post-processor with an + empty name will be ignored. - `-only=foo,bar,baz` - Only build the builds with the given comma-separated names. Build names by default are the names of their builders, unless a diff --git a/website/source/docs/templates/post-processors.html.md b/website/source/docs/templates/post-processors.html.md index b656dd72a..8b041d73b 100644 --- a/website/source/docs/templates/post-processors.html.md +++ b/website/source/docs/templates/post-processors.html.md @@ -38,7 +38,8 @@ defined builders and send it through the post-processors. This means that if you have one post-processor defined and two builders defined in a template, the post-processor will run twice (once for each builder), by default. There are ways, which will be covered later, to control what builders post-processors -apply to, if you wish. +apply to, if you wish. It is also possible to prevent a post-processor from +running. ## Post-Processor Definition @@ -136,21 +137,41 @@ post-processor requested that the input be kept, so it will keep it around. ## Run on Specific Builds -You can use the `only` or `except` configurations to run a post-processor only -with specific builds. These two configurations do what you expect: `only` will -only run the post-processor on the specified builds and `except` will run the -post-processor on anything other than the specified builds. +You can use the `only` or `except` fields to run a post-processor only with +specific builds. These two fields do what you expect: `only` will only run the +post-processor on the specified builds and `except` will run the post-processor +on anything other than the specified builds. A sequence of post-processors will +execute until a skipped post-processor. An example of `only` being used is shown below, but the usage of `except` is effectively the same. `only` and `except` can only be specified on "detailed" -configurations. If you have a sequence of post-processors to run, `only` and -`except` will only affect that single post-processor in the sequence. +fields. If you have a sequence of post-processors to run, `only` and `except` +will affect that post-processor and stop the sequence. + +The `-except` option can specifically skip a named post processor. The `-only` +option *ignores* post-processors. ``` json -{ - "type": "vagrant", - "only": ["virtualbox-iso"] -} +[ + { + // can be skipped when running `packer build -except vbox` + "name": "vbox", + "type": "vagrant", + "only": ["virtualbox-iso"] + }, + { + "type": "compress" // will only be executed when vbox is + } +], +[ + "compress", // will run even if vbox is skipped, from the same start as vbox. + { + "type": "upload", + "endpoint": "http://example.com" + } + // this list of post processors will execute + // using build, not another post-processor. +] ``` The values within `only` or `except` are *build names*, not builder types. If