Repository: docker/compose-cli
Pull request #1787 (2021-06-14 12:56:45)

`compose down -v` also removes anonymous volumes
**What I did**
Pass `volume` option to `ContainerRemove` on `compose down` to also drop anonymous volumes

**Related issue**
close https://github.com/docker/compose-cli/issues/1755

**(not mandatory) A picture of a cute animal, if possible in relation with what you did**



Patch:
diff --git a/local/compose/build.go b/local/compose/build.go
index f68b6e22..c9b32290 100644
--- a/local/compose/build.go
+++ b/local/compose/build.go
@@ -232,7 +232,7 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
 	for _, c := range observedState {
 		for imageName := range opts {
 			if c.Image == imageName {
-				err = s.removeContainers(ctx, cw, []moby.Container{c}, nil)
+				err = s.removeContainers(ctx, cw, []moby.Container{c}, nil, false)
 				if err != nil {
 					return nil, err
 				}
diff --git a/local/compose/create.go b/local/compose/create.go
index d4c9ddd0..d1428d50 100644
--- a/local/compose/create.go
+++ b/local/compose/create.go
@@ -92,7 +92,7 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
 	if len(orphans) > 0 {
 		if options.RemoveOrphans {
 			w := progress.ContextWriter(ctx)
-			err := s.removeContainers(ctx, w, orphans, nil)
+			err := s.removeContainers(ctx, w, orphans, nil, false)
 			if err != nil {
 				return err
 			}
diff --git a/local/compose/down.go b/local/compose/down.go
index c4f42178..c3873883 100644
--- a/local/compose/down.go
+++ b/local/compose/down.go
@@ -66,7 +66,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options c
 
 	err = InReverseDependencyOrder(ctx, options.Project, func(c context.Context, service types.ServiceConfig) error {
 		serviceContainers := containers.filter(isService(service.Name))
-		err := s.removeContainers(ctx, w, serviceContainers, options.Timeout)
+		err := s.removeContainers(ctx, w, serviceContainers, options.Timeout, options.Volumes)
 		return err
 	})
 	if err != nil {
@@ -75,7 +75,7 @@ func (s *composeService) down(ctx context.Context, projectName string, options c
 
 	orphans := containers.filter(isNotService(options.Project.ServiceNames()...))
 	if options.RemoveOrphans && len(orphans) > 0 {
-		err := s.removeContainers(ctx, w, orphans, options.Timeout)
+		err := s.removeContainers(ctx, w, orphans, options.Timeout, false)
 		if err != nil {
 			return err
 		}
@@ -215,7 +215,7 @@ func (s *composeService) stopContainers(ctx context.Context, w progress.Writer,
 	return eg.Wait()
 }
 
-func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, containers []moby.Container, timeout *time.Duration) error {
+func (s *composeService) removeContainers(ctx context.Context, w progress.Writer, containers []moby.Container, timeout *time.Duration, volumes bool) error {
 	eg, _ := errgroup.WithContext(ctx)
 	for _, container := range containers {
 		toDelete := container
@@ -228,7 +228,10 @@ func (s *composeService) removeContainers(ctx context.Context, w progress.Writer
 				return err
 			}
 			w.Event(progress.RemovingEvent(eventName))
-			err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{Force: true})
+			err = s.apiClient.ContainerRemove(ctx, toDelete.ID, moby.ContainerRemoveOptions{
+				Force:         true,
+				RemoveVolumes: volumes,
+			})
 			if err != nil {
 				w.Event(progress.ErrorMessageEvent(eventName, "Error while Removing"))
 				return err


Test patch:
diff --git a/local/compose/down_test.go b/local/compose/down_test.go
index b4bc37b0..26e5baf8 100644
--- a/local/compose/down_test.go
+++ b/local/compose/down_test.go
@@ -90,7 +90,7 @@ func TestDownRemoveVolumes(t *testing.T) {
 		[]apitypes.Container{testContainer("service1", "123")}, nil)
 
 	api.EXPECT().ContainerStop(gomock.Any(), "123", nil).Return(nil)
-	api.EXPECT().ContainerRemove(gomock.Any(), "123", apitypes.ContainerRemoveOptions{Force: true}).Return(nil)
+	api.EXPECT().ContainerRemove(gomock.Any(), "123", apitypes.ContainerRemoveOptions{Force: true, RemoveVolumes: true}).Return(nil)
 
 	api.EXPECT().NetworkList(gomock.Any(), apitypes.NetworkListOptions{Filters: filters.NewArgs(projectFilter(testProject))}).Return(nil, nil)