From a473341058044bae569408b0ebbb2ad0840b533f Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 9 Sep 2025 16:24:05 +0200 Subject: [PATCH] volume ls command can run without a project Signed-off-by: Nicolas De Loof --- cmd/compose/volumes.go | 19 ++++++++----------- pkg/api/api.go | 2 +- pkg/compose/volumes.go | 9 +++------ pkg/compose/volumes_test.go | 6 ++---- pkg/mocks/mock_docker_compose_api.go | 14 +------------- 5 files changed, 15 insertions(+), 35 deletions(-) diff --git a/cmd/compose/volumes.go b/cmd/compose/volumes.go index d98f71db3..456f586fc 100644 --- a/cmd/compose/volumes.go +++ b/cmd/compose/volumes.go @@ -55,24 +55,21 @@ func volumesCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Servic } func runVol(ctx context.Context, dockerCli command.Cli, backend api.Service, services []string, options volumesOptions) error { - project, _, err := options.projectOrName(ctx, dockerCli, services...) + project, name, err := options.projectOrName(ctx, dockerCli, services...) if err != nil { return err } - names := project.ServiceNames() - - if len(services) == 0 { - services = names - } - - for _, service := range services { - if !slices.Contains(names, service) { - return fmt.Errorf("no such service: %s", service) + if project != nil { + names := project.ServiceNames() + for _, service := range services { + if !slices.Contains(names, service) { + return fmt.Errorf("no such service: %s", service) + } } } - volumes, err := backend.Volumes(ctx, project, api.VolumesOptions{ + volumes, err := backend.Volumes(ctx, name, api.VolumesOptions{ Services: services, }) if err != nil { diff --git a/pkg/api/api.go b/pkg/api/api.go index 51140757a..83fda7f50 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -101,7 +101,7 @@ type Service interface { // Generate generates a Compose Project from existing containers Generate(ctx context.Context, options GenerateOptions) (*types.Project, error) // Volumes executes the equivalent to a `docker volume ls` - Volumes(ctx context.Context, project *types.Project, options VolumesOptions) ([]VolumesSummary, error) + Volumes(ctx context.Context, project string, options VolumesOptions) ([]VolumesSummary, error) } type VolumesOptions struct { diff --git a/pkg/compose/volumes.go b/pkg/compose/volumes.go index 8c7bbed2f..0967a719d 100644 --- a/pkg/compose/volumes.go +++ b/pkg/compose/volumes.go @@ -20,18 +20,15 @@ import ( "context" "slices" - "github.com/compose-spec/compose-go/v2/types" "github.com/docker/compose/v2/pkg/api" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/volume" ) -func (s *composeService) Volumes(ctx context.Context, project *types.Project, options api.VolumesOptions) ([]api.VolumesSummary, error) { - projectName := project.Name - +func (s *composeService) Volumes(ctx context.Context, project string, options api.VolumesOptions) ([]api.VolumesSummary, error) { allContainers, err := s.apiClient().ContainerList(ctx, container.ListOptions{ - Filters: filters.NewArgs(projectFilter(projectName)), + Filters: filters.NewArgs(projectFilter(project)), }) if err != nil { return nil, err @@ -51,7 +48,7 @@ func (s *composeService) Volumes(ctx context.Context, project *types.Project, op } volumesResponse, err := s.apiClient().VolumeList(ctx, volume.ListOptions{ - Filters: filters.NewArgs(projectFilter(projectName)), + Filters: filters.NewArgs(projectFilter(project)), }) if err != nil { return nil, err diff --git a/pkg/compose/volumes_test.go b/pkg/compose/volumes_test.go index 8e149159b..ab0fbcc79 100644 --- a/pkg/compose/volumes_test.go +++ b/pkg/compose/volumes_test.go @@ -20,7 +20,6 @@ import ( "context" "testing" - "github.com/compose-spec/compose-go/v2/types" "github.com/docker/compose/v2/pkg/api" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -59,7 +58,6 @@ func TestVolumes(t *testing.T) { } ctx := context.Background() - project := &types.Project{Name: testProject} args := filters.NewArgs(projectFilter(testProject)) listOpts := container.ListOptions{Filters: args} volumeListArgs := filters.NewArgs(projectFilter(testProject)) @@ -75,14 +73,14 @@ func TestVolumes(t *testing.T) { // Test without service filter - should return all project volumes volumeOptions := api.VolumesOptions{} - volumes, err := tested.Volumes(ctx, project, volumeOptions) + volumes, err := tested.Volumes(ctx, testProject, volumeOptions) expected := []api.VolumesSummary{vol1, vol2, vol3} assert.NilError(t, err) assert.DeepEqual(t, volumes, expected) // Test with service filter - should only return volumes used by service1 volumeOptions = api.VolumesOptions{Services: []string{"service1"}} - volumes, err = tested.Volumes(ctx, project, volumeOptions) + volumes, err = tested.Volumes(ctx, testProject, volumeOptions) expected = []api.VolumesSummary{vol1, vol2} assert.NilError(t, err) assert.DeepEqual(t, volumes, expected) diff --git a/pkg/mocks/mock_docker_compose_api.go b/pkg/mocks/mock_docker_compose_api.go index 830d7e1af..be7cea3ca 100644 --- a/pkg/mocks/mock_docker_compose_api.go +++ b/pkg/mocks/mock_docker_compose_api.go @@ -499,7 +499,7 @@ func (mr *MockServiceMockRecorder) Viz(ctx, project, options any) *gomock.Call { } // Volumes mocks base method. -func (m *MockService) Volumes(ctx context.Context, project *types.Project, options api.VolumesOptions) ([]api.VolumesSummary, error) { +func (m *MockService) Volumes(ctx context.Context, project string, options api.VolumesOptions) ([]api.VolumesSummary, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Volumes", ctx, project, options) ret0, _ := ret[0].([]api.VolumesSummary) @@ -589,18 +589,6 @@ func (mr *MockLogConsumerMockRecorder) Log(containerName, message any) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log", reflect.TypeOf((*MockLogConsumer)(nil).Log), containerName, message) } -// Register mocks base method. -func (m *MockLogConsumer) Register(container string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Register", container) -} - -// Register indicates an expected call of Register. -func (mr *MockLogConsumerMockRecorder) Register(container any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Register", reflect.TypeOf((*MockLogConsumer)(nil).Register), container) -} - // Status mocks base method. func (m *MockLogConsumer) Status(container, msg string) { m.ctrl.T.Helper()