From 11f331280e74f22d941a569cdb6746d625fb6b49 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Sun, 31 Jul 2022 16:45:32 +0200 Subject: [PATCH] bake(compose): allow dot in target name Signed-off-by: CrazyMax --- bake/bake.go | 11 ++++++ bake/bake_test.go | 61 +++++++++++++++++++++++++++++ bake/compose.go | 13 +++--- bake/compose_test.go | 2 +- commands/bake.go | 4 +- docs/guides/bake/file-definition.md | 1 + 6 files changed, 83 insertions(+), 9 deletions(-) diff --git a/bake/bake.go b/bake/bake.go index 4c5897572f8c..c810933a682a 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -90,6 +90,10 @@ func ReadTargets(ctx context.Context, files []File, targets, overrides []string, return nil, nil, err } + for i, t := range targets { + targets[i] = sanitizeTargetName(t) + } + o, err := c.newOverrides(overrides) if err != nil { return nil, nil, err @@ -976,6 +980,13 @@ func validateTargetName(name string) error { return nil } +func sanitizeTargetName(target string) string { + // as stipulated in compose spec, service name can contain a dot so as + // best-effort and to avoid any potential ambiguity, we replace the dot + // with an underscore. + return strings.ReplaceAll(target, ".", "_") +} + func sliceEqual(s1, s2 []string) bool { if len(s1) != len(s2) { return false diff --git a/bake/bake_test.go b/bake/bake_test.go index 1670382dde67..41b45df212b9 100644 --- a/bake/bake_test.go +++ b/bake/bake_test.go @@ -307,6 +307,67 @@ services: require.Equal(t, []string{"db", "newservice", "webapp"}, g[0].Targets) } +func TestReadTargetsWithDotCompose(t *testing.T) { + t.Parallel() + + fp := File{ + Name: "docker-compose.yml", + Data: []byte( + `version: "3" +services: + web.app: + build: + dockerfile: Dockerfile.webapp + args: + buildno: 1 +`), + } + + fp2 := File{ + Name: "docker-compose2.yml", + Data: []byte( + `version: "3" +services: + web_app: + build: + args: + buildno2: 12 +`), + } + + ctx := context.TODO() + + m, g, err := ReadTargets(ctx, []File{fp}, []string{"web.app"}, nil, nil) + require.NoError(t, err) + require.Equal(t, 1, len(m)) + _, ok := m["web_app"] + require.True(t, ok) + require.Equal(t, "Dockerfile.webapp", *m["web_app"].Dockerfile) + require.Equal(t, "1", m["web_app"].Args["buildno"]) + + m, g, err = ReadTargets(ctx, []File{fp2}, []string{"web_app"}, nil, nil) + require.NoError(t, err) + require.Equal(t, 1, len(m)) + _, ok = m["web_app"] + require.True(t, ok) + require.Equal(t, "Dockerfile", *m["web_app"].Dockerfile) + require.Equal(t, "12", m["web_app"].Args["buildno2"]) + + m, g, err = ReadTargets(ctx, []File{fp, fp2}, []string{"default"}, nil, nil) + require.NoError(t, err) + require.Equal(t, 1, len(m)) + _, ok = m["web_app"] + require.True(t, ok) + require.Equal(t, "Dockerfile.webapp", *m["web_app"].Dockerfile) + require.Equal(t, ".", *m["web_app"].Context) + require.Equal(t, "1", m["web_app"].Args["buildno"]) + require.Equal(t, "12", m["web_app"].Args["buildno2"]) + + require.Equal(t, 1, len(g)) + sort.Strings(g[0].Targets) + require.Equal(t, []string{"web_app"}, g[0].Targets) +} + func TestHCLCwdPrefix(t *testing.T) { fp := File{ Name: "docker-bake.hcl", diff --git a/bake/compose.go b/bake/compose.go index 37e7782ed645..d74762560d62 100644 --- a/bake/compose.go +++ b/bake/compose.go @@ -61,8 +61,9 @@ func ParseCompose(dt []byte) (*Config, error) { s.Build = &compose.BuildConfig{} } - if err = validateTargetName(s.Name); err != nil { - return nil, errors.Wrapf(err, "invalid service name %q", s.Name) + targetName := sanitizeTargetName(s.Name) + if err = validateTargetName(targetName); err != nil { + return nil, errors.Wrapf(err, "invalid service name %q", targetName) } var contextPathP *string @@ -85,9 +86,9 @@ func ParseCompose(dt []byte) (*Config, error) { secrets = append(secrets, secret) } - g.Targets = append(g.Targets, s.Name) + g.Targets = append(g.Targets, targetName) t := &Target{ - Name: s.Name, + Name: targetName, Context: contextPathP, Dockerfile: dockerfilePathP, Tags: s.Build.Tags, @@ -220,13 +221,13 @@ func (t *Target) composeExtTarget(exts map[string]interface{}) error { return nil } -// compposeValidate validates a compose file +// composeValidate validates a compose file func composeValidate(project *compose.Project) error { for _, s := range project.Services { if s.Build != nil { for _, secret := range s.Build.Secrets { if _, ok := project.Secrets[secret.Source]; !ok { - return errors.Wrap(errComposeInvalid, fmt.Sprintf("service %q refers to undefined build secret %s", s.Name, secret.Source)) + return errors.Wrap(errComposeInvalid, fmt.Sprintf("service %q refers to undefined build secret %s", sanitizeTargetName(s.Name), secret.Source)) } } } diff --git a/bake/compose_test.go b/bake/compose_test.go index a3af03b924d6..15bbfa7fc382 100644 --- a/bake/compose_test.go +++ b/bake/compose_test.go @@ -418,7 +418,7 @@ func TestServiceName(t *testing.T) { }, { svc: "a.b", - wantErr: true, + wantErr: false, }, { svc: "_a", diff --git a/commands/bake.go b/commands/bake.go index 53d2f6715e59..782541ebbd5e 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -104,8 +104,8 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error } tgts, grps, err := bake.ReadTargets(ctx, files, targets, overrides, map[string]string{ - // Don't forget to update documentation if you add a new - // built-in variable: docs/reference/buildx_bake.md#built-in-variables + // don't forget to update documentation if you add a new + // built-in variable: docs/guides/bake/file-definition.md#built-in-variables "BAKE_CMD_CONTEXT": cmdContext, "BAKE_LOCAL_PLATFORM": platforms.DefaultString(), }) diff --git a/docs/guides/bake/file-definition.md b/docs/guides/bake/file-definition.md index 4825b19bcf38..a993bdf97e2c 100644 --- a/docs/guides/bake/file-definition.md +++ b/docs/guides/bake/file-definition.md @@ -36,6 +36,7 @@ $ docker buildx bake webapp-dev > **Note** > > In the case of compose files, each service corresponds to a target. +> If compose service name contains a dot it will be replaced with an underscore. Complete list of valid target fields available for [HCL](#hcl-definition) and [JSON](#json-definition) definitions: