diff --git a/cmd/compose/create.go b/cmd/compose/create.go index 717c28b31c..50e7a6f796 100644 --- a/cmd/compose/create.go +++ b/cmd/compose/create.go @@ -126,6 +126,9 @@ func (opts createOptions) Apply(project *types.Project) { if opts.noBuild { for i, service := range project.Services { service.Build = nil + if service.Image == "" { + service.Image = api.GetImageNameOrDefault(service, project.Name) + } project.Services[i] = service } } diff --git a/pkg/api/api.go b/pkg/api/api.go index 08f6433d8f..43f6745a6f 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -445,3 +445,12 @@ const ( // UserCancel user cancelled compose up, we are stopping containers UserCancel ) + +// GetImageNameOrDefault computes the default image name for a service, used to tag built images +func GetImageNameOrDefault(service types.ServiceConfig, projectName string) string { + imageName := service.Image + if imageName == "" { + imageName = projectName + "_" + service.Name + } + return imageName +} diff --git a/pkg/compose/build.go b/pkg/compose/build.go index 7581a664d9..937bfd361a 100644 --- a/pkg/compose/build.go +++ b/pkg/compose/build.go @@ -64,7 +64,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti if service.Build == nil { continue } - imageName := getImageName(service, project.Name) + imageName := api.GetImageNameOrDefault(service, project.Name) imagesToBuild = append(imagesToBuild, imageName) buildOptions, err := s.toBuildOptions(project, service, imageName, options.SSHs) if err != nil { @@ -135,7 +135,7 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types. } // set digest as com.docker.compose.image label so we can detect outdated containers for i, service := range project.Services { - image := getImageName(service, project.Name) + image := api.GetImageNameOrDefault(service, project.Name) digest, ok := images[image] if ok { if project.Services[i].Labels == nil { @@ -154,7 +154,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri if service.Image == "" && service.Build == nil { return nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name) } - imageName := getImageName(service, project.Name) + imageName := api.GetImageNameOrDefault(service, project.Name) _, localImagePresent := images[imageName] if service.Build != nil { @@ -176,7 +176,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri func (s *composeService) getLocalImagesDigests(ctx context.Context, project *types.Project) (map[string]string, error) { var imageNames []string for _, s := range project.Services { - imgName := getImageName(s, project.Name) + imgName := api.GetImageNameOrDefault(s, project.Name) if !utils.StringContains(imageNames, imgName) { imageNames = append(imageNames, imgName) } @@ -191,7 +191,7 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ } for i := range project.Services { - imgName := getImageName(project.Services[i], project.Name) + imgName := api.GetImageNameOrDefault(project.Services[i], project.Name) digest, ok := images[imgName] if ok { project.Services[i].CustomLabels.Add(api.ImageDigestLabel, digest) diff --git a/pkg/compose/build_classic.go b/pkg/compose/build_classic.go index db5d948e32..dc88dee3ff 100644 --- a/pkg/compose/build_classic.go +++ b/pkg/compose/build_classic.go @@ -29,6 +29,7 @@ import ( "github.com/compose-spec/compose-go/types" buildx "github.com/docker/buildx/build" "github.com/docker/cli/cli/command/image/build" + "github.com/docker/compose/v2/pkg/api" dockertypes "github.com/docker/docker/api/types" "github.com/docker/docker/cli" "github.com/docker/docker/pkg/archive" @@ -45,7 +46,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj var nameDigests = make(map[string]string) var errs error err := project.WithServices(nil, func(service types.ServiceConfig) error { - imageName := getImageName(service, project.Name) + imageName := api.GetImageNameOrDefault(service, project.Name) o, ok := opts[imageName] if !ok { return nil diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 8801436fc0..7bc16777c0 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -227,14 +227,6 @@ func (s *composeService) ensureProjectVolumes(ctx context.Context, project *type return nil } -func getImageName(service types.ServiceConfig, projectName string) string { - imageName := service.Image - if imageName == "" { - imageName = projectName + "_" + service.Name - } - return imageName -} - func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, service types.ServiceConfig, number int, inherit *moby.Container, autoRemove bool, attachStdin bool) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { @@ -279,7 +271,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, AttachStderr: true, AttachStdout: true, Cmd: runCmd, - Image: getImageName(service, p.Name), + Image: api.GetImageNameOrDefault(service, p.Name), WorkingDir: service.WorkingDir, Entrypoint: entrypoint, NetworkDisabled: service.NetworkMode == "disabled", @@ -712,7 +704,7 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj inherit *moby.Container) (map[string]struct{}, []string, []mount.Mount, error) { var mounts = []mount.Mount{} - image := getImageName(service, p.Name) + image := api.GetImageNameOrDefault(service, p.Name) imgInspect, _, err := s.apiClient().ImageInspectWithRaw(ctx, image) if err != nil { return nil, nil, nil, err diff --git a/pkg/compose/create_test.go b/pkg/compose/create_test.go index cdcc4ad61d..cc44478e17 100644 --- a/pkg/compose/create_test.go +++ b/pkg/compose/create_test.go @@ -22,10 +22,12 @@ import ( "sort" "testing" - composetypes "github.com/compose-spec/compose-go/types" "github.com/docker/compose/v2/pkg/api" + + composetypes "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" mountTypes "github.com/docker/docker/api/types/mount" + "gotest.tools/v3/assert" ) @@ -77,8 +79,8 @@ func TestBuildVolumeMount(t *testing.T) { } func TestServiceImageName(t *testing.T) { - assert.Equal(t, getImageName(composetypes.ServiceConfig{Image: "myImage"}, "myProject"), "myImage") - assert.Equal(t, getImageName(composetypes.ServiceConfig{Name: "aService"}, "myProject"), "myProject_aService") + assert.Equal(t, api.GetImageNameOrDefault(composetypes.ServiceConfig{Image: "myImage"}, "myProject"), "myImage") + assert.Equal(t, api.GetImageNameOrDefault(composetypes.ServiceConfig{Name: "aService"}, "myProject"), "myProject_aService") } func TestPrepareNetworkLabels(t *testing.T) { diff --git a/pkg/compose/down.go b/pkg/compose/down.go index 1ea7b4dcb0..4251a8dc1e 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -195,7 +195,7 @@ func (s *composeService) getServiceImages(options api.DownOptions, project *type continue } if image == "" { - image = getImageName(service, project.Name) + image = api.GetImageNameOrDefault(service, project.Name) } images[image] = struct{}{} }