Repository: docker/compose (go)

Issue:
[BUG] Removing containers when none are running results in output artifact `[]`
### Description

Running `docker compose rm` when no containers are running results in the `[]` string being written to the output.

This output artifact was not there before and seems to have been introduced in one of the 2.17.x versions, although I didn't pinpoint which one exactly.

Seems to be nothing more than a minor cosmetic thing, but thought I should raise it nonetheless.

### Steps To Reproduce

With any valid configuration
```
services:
  c:
    image: busybox
    command: /bin/true
```

Run `docker compose rm`.

Output:
```
[]
No stopped containers
```

### Compose Version

```Text
Docker Compose version v2.17.3
```


### Docker Environment

_No response_

### Anything else?

_No response_

Pull request:
fix: remove unnecessary [] output
Fixes #10550 

Patch:
diff --git a/pkg/compose/down.go b/pkg/compose/down.go
index 1046b764b..7c4def35a 100644
--- a/pkg/compose/down.go
+++ b/pkg/compose/down.go
@@ -181,29 +181,43 @@ func (s *composeService) removeNetwork(ctx context.Context, name string, w progr
 	eventName := fmt.Sprintf("Network %s", name)
 	w.Event(progress.RemovingEvent(eventName))
 
-	var removed int
+	var found int
 	for _, net := range networks {
-		if net.Name == name {
-			if err := s.apiClient().NetworkRemove(ctx, net.ID); err != nil {
-				if errdefs.IsNotFound(err) {
-					continue
-				}
-				w.Event(progress.ErrorEvent(eventName))
-				return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name))
+		if net.Name != name {
+			continue
+		}
+		network, err := s.apiClient().NetworkInspect(ctx, net.ID, moby.NetworkInspectOptions{})
+		if errdefs.IsNotFound(err) {
+			w.Event(progress.NewEvent(eventName, progress.Warning, "No resource found to remove"))
+			return nil
+		}
+		if err != nil {
+			return err
+		}
+		if len(network.Containers) > 0 {
+			w.Event(progress.NewEvent(eventName, progress.Warning, "Resource is still in use"))
+			found++
+			continue
+		}
+
+		if err := s.apiClient().NetworkRemove(ctx, net.ID); err != nil {
+			if errdefs.IsNotFound(err) {
+				continue
 			}
-			removed++
+			w.Event(progress.ErrorEvent(eventName))
+			return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name))
 		}
+		w.Event(progress.RemovedEvent(eventName))
+		found++
 	}
 
-	if removed == 0 {
+	if found == 0 {
 		// in practice, it's extremely unlikely for this to ever occur, as it'd
 		// mean the network was present when we queried at the start of this
 		// method but was then deleted by something else in the interim
-		w.Event(progress.NewEvent(eventName, progress.Done, "Warning: No resource found to remove"))
+		w.Event(progress.NewEvent(eventName, progress.Warning, "No resource found to remove"))
 		return nil
 	}
-
-	w.Event(progress.RemovedEvent(eventName))
 	return nil
 }
 
diff --git a/pkg/compose/remove.go b/pkg/compose/remove.go
index 0d684a12b..79511be3f 100644
--- a/pkg/compose/remove.go
+++ b/pkg/compose/remove.go
@@ -75,7 +75,6 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
 	stoppedContainers.forEach(func(c moby.Container) {
 		names = append(names, getCanonicalContainerName(c))
 	})
-	fmt.Fprintln(s.stdinfo(), names)
 
 	if len(names) == 0 {
 		fmt.Fprintln(s.stdinfo(), "No stopped containers")


Test patch:
diff --git a/pkg/compose/down_test.go b/pkg/compose/down_test.go
index 72827a521..78f5be280 100644
--- a/pkg/compose/down_test.go
+++ b/pkg/compose/down_test.go
@@ -79,6 +79,8 @@ func TestDown(t *testing.T) {
 		{ID: "abc123", Name: "myProject_default"},
 		{ID: "def456", Name: "myProject_default"},
 	}, nil)
+	api.EXPECT().NetworkInspect(gomock.Any(), "abc123", gomock.Any()).Return(moby.NetworkResource{ID: "abc123"}, nil)
+	api.EXPECT().NetworkInspect(gomock.Any(), "def456", gomock.Any()).Return(moby.NetworkResource{ID: "def456"}, nil)
 	api.EXPECT().NetworkRemove(gomock.Any(), "abc123").Return(nil)
 	api.EXPECT().NetworkRemove(gomock.Any(), "def456").Return(nil)
 
@@ -118,6 +120,7 @@ func TestDownRemoveOrphans(t *testing.T) {
 	api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{
 		Filters: filters.NewArgs(filters.Arg("name", "myProject_default")),
 	}).Return([]moby.NetworkResource{{ID: "abc123", Name: "myProject_default"}}, nil)
+	api.EXPECT().NetworkInspect(gomock.Any(), "abc123", gomock.Any()).Return(moby.NetworkResource{ID: "abc123"}, nil)
 	api.EXPECT().NetworkRemove(gomock.Any(), "abc123").Return(nil)
 
 	err := tested.Down(context.Background(), strings.ToLower(testProject), compose.DownOptions{RemoveOrphans: true})