From 39f63ecb5e81dcdd0d5108f8819ddb5d131206f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 22 Apr 2024 22:30:41 +0200 Subject: [PATCH] feat: support overriding the default recreate options for compose (#2511) * feat: support overriding the default recreate options for compose * chore: validate recreation values --- docs/features/docker_compose.md | 8 ++++++-- modules/compose/compose.go | 14 ++++++++++++++ modules/compose/compose_api.go | 23 +++++++++++++++++++++++ modules/compose/compose_api_test.go | 17 +++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/docs/features/docker_compose.md b/docs/features/docker_compose.md index bfb4f90b16..8a2d068792 100644 --- a/docs/features/docker_compose.md +++ b/docs/features/docker_compose.md @@ -61,7 +61,9 @@ Use the advanced `NewDockerComposeWith(...)` constructor allowing you to customi #### Compose Up options -- `RemoveOrphans`: remove orphaned containers after the stack is stopped. +- `Recreate`: recreate the containers. If any other value than `api.RecreateNever`, `api.RecreateForce` or `api.RecreateDiverged` is provided, the default value `api.RecreateForce` will be used. +- `RecreateDependencies`: recreate dependent containers. If any other value than `api.RecreateNever`, `api.RecreateForce` or `api.RecreateDiverged` is provided, the default value `api.RecreateForce` will be used. +- `RemoveOrphans`: remove orphaned containers when the stack is upped. - `Wait`: will wait until the containers reached the running|healthy state. #### Compose Down options @@ -80,6 +82,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/docker/compose/v2/pkg/api" tc "github.com/testcontainers/testcontainers-go/modules/compose" ) @@ -95,7 +99,7 @@ func TestSomethingElse(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - require.NoError(t, compose.Up(ctx, tc.Wait(true)), "compose.Up()") + require.NoError(t, compose.Up(ctx, tc.WithRecreate(api.RecreateNever), tc.Wait(true)), "compose.Up()") // do some testing here } diff --git a/modules/compose/compose.go b/modules/compose/compose.go index 90f3fd804d..cc4a6f9b8a 100644 --- a/modules/compose/compose.go +++ b/modules/compose/compose.go @@ -93,6 +93,20 @@ type waitService struct { publishedPort int } +// WithRecreate defines the strategy to apply on existing containers. If any other value than +// api.RecreateNever, api.RecreateForce or api.RecreateDiverged is provided, the default value +// api.RecreateForce will be used. +func WithRecreate(recreate string) StackUpOption { + return Recreate(recreate) +} + +// WithRecreateDependencies defines the strategy to apply on container dependencies. If any other value than +// api.RecreateNever, api.RecreateForce or api.RecreateDiverged is provided, the default value +// api.RecreateForce will be used. +func WithRecreateDependencies(recreate string) StackUpOption { + return RecreateDependencies(recreate) +} + func WithStackFiles(filePaths ...string) ComposeStackOption { return ComposeStackFiles(filePaths) } diff --git a/modules/compose/compose_api.go b/modules/compose/compose_api.go index 8f8ea5320b..d80d8e9fa7 100644 --- a/modules/compose/compose_api.go +++ b/modules/compose/compose_api.go @@ -59,6 +59,29 @@ func (io IgnoreOrphans) applyToStackUp(co *api.CreateOptions, _ *api.StartOption co.IgnoreOrphans = bool(io) } +// Recreate will recreate the containers that are already running +type Recreate string + +func (r Recreate) applyToStackUp(o *stackUpOptions) { + o.Recreate = validateRecreate(string(r)) +} + +// RecreateDependencies will recreate the dependencies of the services that are already running +type RecreateDependencies string + +func (r RecreateDependencies) applyToStackUp(o *stackUpOptions) { + o.RecreateDependencies = validateRecreate(string(r)) +} + +func validateRecreate(r string) string { + switch r { + case api.RecreateDiverged, api.RecreateForce, api.RecreateNever: + return r + default: + return api.RecreateForce + } +} + // RemoveOrphans will clean up containers that are not declared on the compose model but own the same labels type RemoveOrphans bool diff --git a/modules/compose/compose_api_test.go b/modules/compose/compose_api_test.go index d703934669..1a203347ec 100644 --- a/modules/compose/compose_api_test.go +++ b/modules/compose/compose_api_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/docker/compose/v2/pkg/api" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/volume" "github.com/google/uuid" @@ -563,6 +564,22 @@ func TestDockerComposeAPIWithVolume(t *testing.T) { require.NoError(t, err, "compose.Up()") } +func TestDockerComposeAPIWithRecreate(t *testing.T) { + path, _ := RenderComposeComplex(t) + compose, err := NewDockerCompose(path) + require.NoError(t, err, "NewDockerCompose()") + + t.Cleanup(func() { + require.NoError(t, compose.Down(context.Background(), RemoveOrphans(true), RemoveImagesLocal), "compose.Down()") + }) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + err = compose.Up(ctx, WithRecreate(api.RecreateNever), WithRecreateDependencies(api.RecreateNever), Wait(true)) + require.NoError(t, err, "compose.Up()") +} + func TestDockerComposeAPIVolumesDeletedOnDown(t *testing.T) { path := RenderComposeWithVolume(t) identifier := uuid.New().String()