diff --git a/internal/stop/stop_test.go b/internal/stop/stop_test.go index da571330b..b607d87d7 100644 --- a/internal/stop/stop_test.go +++ b/internal/stop/stop_test.go @@ -13,6 +13,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/volume" + "github.com/docker/docker/client" "github.com/h2non/gock" "github.com/spf13/afero" "github.com/stretchr/testify/assert" @@ -206,6 +207,24 @@ func TestStopServices(t *testing.T) { assert.Empty(t, apitest.ListUnmatchedRequests()) }) + t.Run("skips all filter when removing data volumes with Docker version pre-v1.42", func(t *testing.T) { + utils.DbId = "test-db" + utils.ConfigId = "test-config" + utils.StorageId = "test-storage" + utils.EdgeRuntimeId = "test-functions" + utils.InbucketId = "test-inbucket" + // Setup mock docker + require.NoError(t, apitest.MockDocker(utils.Docker)) + require.NoError(t, client.WithVersion("1.41")(utils.Docker)) + defer gock.OffAll() + apitest.MockDockerStop(utils.Docker) + // Run test + err := stop(context.Background(), false, io.Discard, utils.Config.ProjectId) + // Check error + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) + t.Run("throws error on prune failure", func(t *testing.T) { // Setup mock docker require.NoError(t, apitest.MockDocker(utils.Docker)) diff --git a/internal/testing/apitest/docker.go b/internal/testing/apitest/docker.go index 21a4d7dd2..556756dfd 100644 --- a/internal/testing/apitest/docker.go +++ b/internal/testing/apitest/docker.go @@ -9,9 +9,11 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" + "github.com/go-errors/errors" "github.com/h2non/gock" ) @@ -64,6 +66,12 @@ func MockDockerStop(docker *client.Client) { Post("/v" + docker.ClientVersion() + "/containers/prune"). Reply(http.StatusOK). JSON(container.PruneReport{}) + if !versions.GreaterThanOrEqualTo(docker.ClientVersion(), "1.42") { + gock.New(docker.DaemonHost()). + Post("/v"+docker.ClientVersion()+"/volumes/prune"). + MatchParam("filters", `"all":{"true":true}`). + ReplyError(errors.New(`failed to parse filters for all=true&label=com.supabase.cli.project%3Dtest: "all" is an invalid volume filter`)) + } gock.New(docker.DaemonHost()). Post("/v" + docker.ClientVersion() + "/volumes/prune"). Reply(http.StatusOK). diff --git a/internal/utils/docker.go b/internal/utils/docker.go index 6264c4056..84911d07f 100644 --- a/internal/utils/docker.go +++ b/internal/utils/docker.go @@ -25,6 +25,7 @@ import ( "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/client" "github.com/docker/docker/errdefs" @@ -125,10 +126,12 @@ func DockerRemoveAll(ctx context.Context, w io.Writer, projectId string) error { } // Remove named volumes if NoBackupVolume { - // Since docker engine 25.0.3, all flag is required to include named volumes. - // https://github.com/docker/cli/blob/master/cli/command/volume/prune.go#L76 vargs := args.Clone() - vargs.Add("all", "true") + if versions.GreaterThanOrEqualTo(Docker.ClientVersion(), "1.42") { + // Since docker engine 25.0.3, all flag is required to include named volumes. + // https://github.com/docker/cli/blob/master/cli/command/volume/prune.go#L76 + vargs.Add("all", "true") + } if report, err := Docker.VolumesPrune(ctx, vargs); err != nil { return errors.Errorf("failed to prune volumes: %w", err) } else if viper.GetBool("DEBUG") {