diff --git a/docker_test.go b/docker_test.go index 45e276b1ed..bc29e854d0 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1854,7 +1854,7 @@ func TestContainerWithNoUserID(t *testing.T) { } func TestGetGatewayIP(t *testing.T) { - // When using docker-compose with DinD mode, and using host port or http wait strategy + // When using docker compose with DinD mode, and using host port or http wait strategy // It's need to invoke GetGatewayIP for get the host provider, err := providerType.GetProvider(WithLogger(TestLogger(t))) if err != nil { diff --git a/docs/features/docker_compose.md b/docs/features/docker_compose.md index ea2a56bc19..352f2c84eb 100644 --- a/docs/features/docker_compose.md +++ b/docs/features/docker_compose.md @@ -7,7 +7,7 @@ This is intended to be useful on projects where Docker Compose is already used in dev or other environments to define services that an application may be dependent upon. -## Using `docker-compose` directly +## Using `docker compose` directly !!!warning The minimal version of Go required to use this module is **1.21**. @@ -16,9 +16,9 @@ dependent upon. go get github.com/testcontainers/testcontainers-go/modules/compose ``` -Because `docker-compose` v2 is implemented in Go it's possible for _Testcontainers for Go_ to +Because `compose` v2 is implemented in Go it's possible for _Testcontainers for Go_ to use [`github.com/docker/compose`](https://github.com/docker/compose) directly and skip any process execution/_docker-compose-in-a-container_ scenario. -The `ComposeStack` API exposes this variant of using `docker-compose` in an easy way. +The `ComposeStack` API exposes this variant of using `docker compose` in an easy way. ### Basic examples @@ -88,14 +88,14 @@ func TestSomethingElse(t *testing.T) { To interact with service containers after a stack was started it is possible to get an `*tc.DockerContainer` instance via the `ServiceContainer(...)` function. The function takes a **service name** (and a `context.Context`) and returns either a `*tc.DockerContainer` or an `error`. -This is different to the previous `LocalDockerCompose` API where service containers were accessed via their **container name** e.g. `mysql_1` or `mysql-1` (depending on the version of `docker-compose`). +This is different to the previous `LocalDockerCompose` API where service containers were accessed via their **container name** e.g. `mysql_1` or `mysql-1` (depending on the version of `docker compose`). Furthermore, there's the convenience function `Serices()` to get a list of all services **defined** by the current project. Note that not all of them need necessarily be correctly started as the information is based on the given compose files. ### Wait strategies -Just like with regular test containers you can also apply wait strategies to `docker-compose` services. +Just like with regular test containers you can also apply wait strategies to `docker compose` services. The `ComposeStack.WaitForService(...)` function allows you to apply a wait strategy to **a service by name**. All wait strategies are executed in parallel to both improve startup performance by not blocking too long and to fail early if something's wrong. @@ -139,7 +139,7 @@ func TestSomethingWithWaiting(t *testing.T) { ### Compose environment -`docker-compose` supports expansion based on environment variables. +`docker compose` supports expansion based on environment variables. The `ComposeStack` supports this as well in two different variants: - `ComposeStack.WithEnv(m map[string]string) ComposeStack` to parameterize stacks from your test code @@ -150,14 +150,14 @@ The `ComposeStack` supports this as well in two different variants: Also have a look at [ComposeStack](https://pkg.go.dev/github.com/testcontainers/testcontainers-go#ComposeStack) docs for further information. -## Usage of `docker-compose` binary +## Usage of the `docker compose` binary -_Node:_ this API is deprecated and superseded by `ComposeStack` which takes advantage of `docker-compose` v2 being +_Node:_ this API is deprecated and superseded by `ComposeStack` which takes advantage of `compose` v2 being implemented in Go as well by directly using the upstream project. You can override Testcontainers' default behaviour and make it use a -docker-compose binary installed on the local machine. This will generally yield -an experience that is closer to running docker-compose locally, with the caveat +docker compose binary installed on the local machine. This will generally yield +an experience that is closer to running docker compose locally, with the caveat that Docker Compose needs to be present on dev and CI machines. ### Examples diff --git a/modules/compose/compose.go b/modules/compose/compose.go index 75bf55e0aa..242caef501 100644 --- a/modules/compose/compose.go +++ b/modules/compose/compose.go @@ -155,11 +155,12 @@ func NewLocalDockerCompose(filePaths []string, identifier string, opts ...LocalD opts[idx].ApplyToLocalCompose(dc.LocalDockerComposeOptions) } - dc.Executable = "docker-compose" + dc.Executable = "docker" if runtime.GOOS == "windows" { - dc.Executable = "docker-compose.exe" + dc.Executable = "docker.exe" } + dc.composeSubcommand = "compose" dc.ComposeFilePaths = filePaths dc.absComposeFilePaths = make([]string, len(filePaths)) diff --git a/modules/compose/compose_api.go b/modules/compose/compose_api.go index b0ec87ed29..409875537c 100644 --- a/modules/compose/compose_api.go +++ b/modules/compose/compose_api.go @@ -34,7 +34,7 @@ func (f stackDownOptionFunc) applyToStackDown(do *api.DownOptions) { f(do) } -// RunServices is comparable to 'docker-compose run' as it only creates a subset of containers +// RunServices is comparable to 'docker compose run' as it only creates a subset of containers // instead of all services defined by the project func RunServices(serviceNames ...string) StackUpOption { return stackUpOptionFunc(func(o *stackUpOptions) { @@ -231,7 +231,6 @@ func (d *dockerCompose) Up(ctx context.Context, opts ...StackUpOption) error { Wait: upOptions.Wait, }, }) - if err != nil { return err } diff --git a/modules/compose/compose_local.go b/modules/compose/compose_local.go index c008e2ec9d..2be2daf152 100644 --- a/modules/compose/compose_local.go +++ b/modules/compose/compose_local.go @@ -41,12 +41,14 @@ func (c composeVersion2) Format(parts ...string) string { return strings.Join(parts, "-") } +// Deprecated: use ComposeStack instead // LocalDockerCompose represents a Docker Compose execution using local binary -// docker-compose or docker-compose.exe, depending on the underlying platform +// docker compose or docker.exe compose, depending on the underlying platform type LocalDockerCompose struct { ComposeVersion *LocalDockerComposeOptions Executable string + composeSubcommand string ComposeFilePaths []string absComposeFilePaths []string Identifier string @@ -58,17 +60,20 @@ type LocalDockerCompose struct { } type ( + // Deprecated: it will be removed in the next major release // LocalDockerComposeOptions defines options applicable to LocalDockerCompose LocalDockerComposeOptions struct { Logger testcontainers.Logging } + // Deprecated: it will be removed in the next major release // LocalDockerComposeOption defines a common interface to modify LocalDockerComposeOptions // These options can be passed to NewLocalDockerCompose in a variadic way to customize the returned LocalDockerCompose instance LocalDockerComposeOption interface { ApplyToLocalCompose(opts *LocalDockerComposeOptions) } + // Deprecated: it will be removed in the next major release // LocalDockerComposeOptionsFunc is a shorthand to implement the LocalDockerComposeOption interface LocalDockerComposeOptionsFunc func(opts *LocalDockerComposeOptions) ) @@ -86,6 +91,7 @@ func WithLogger(logger testcontainers.Logging) ComposeLoggerOption { } } +// Deprecated: it will be removed in the next major release func (o ComposeLoggerOption) ApplyToLocalCompose(opts *LocalDockerComposeOptions) { opts.Logger = o.logger } @@ -94,15 +100,18 @@ func (o ComposeLoggerOption) applyToComposeStack(opts *composeStackOptions) { opts.Logger = o.logger } +// Deprecated: it will be removed in the next major release func (f LocalDockerComposeOptionsFunc) ApplyToLocalCompose(opts *LocalDockerComposeOptions) { f(opts) } -// Down executes docker-compose down +// Deprecated: it will be removed in the next major release +// Down executes docker compose down func (dc *LocalDockerCompose) Down() ExecError { return executeCompose(dc, []string{"down", "--remove-orphans", "--volumes"}) } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) getDockerComposeEnvironment() map[string]string { environment := map[string]string{} @@ -117,10 +126,12 @@ func (dc *LocalDockerCompose) getDockerComposeEnvironment() map[string]string { return environment } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) containerNameFromServiceName(service, separator string) string { return dc.Identifier + separator + service } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) applyStrategyToRunningContainer() error { cli, err := testcontainers.NewDockerClientWithOpts(context.Background()) if err != nil { @@ -163,17 +174,19 @@ func (dc *LocalDockerCompose) applyStrategyToRunningContainer() error { err = strategy.WaitUntilReady(context.Background(), dockercontainer) if err != nil { - return fmt.Errorf("Unable to apply wait strategy %v to service %s due to %w", strategy, k.service, err) + return fmt.Errorf("unable to apply wait strategy %v to service %s due to %w", strategy, k.service, err) } } return nil } +// Deprecated: it will be removed in the next major release // Invoke invokes the docker compose func (dc *LocalDockerCompose) Invoke() ExecError { return executeCompose(dc, dc.Cmd) } +// Deprecated: it will be removed in the next major release // WaitForService sets the strategy for the service that is to be waited on func (dc *LocalDockerCompose) WaitForService(service string, strategy wait.Strategy) DockerCompose { dc.waitStrategySupplied = true @@ -181,18 +194,21 @@ func (dc *LocalDockerCompose) WaitForService(service string, strategy wait.Strat return dc } +// Deprecated: it will be removed in the next major release // WithCommand assigns the command func (dc *LocalDockerCompose) WithCommand(cmd []string) DockerCompose { dc.Cmd = cmd return dc } +// Deprecated: it will be removed in the next major release // WithEnv assigns the environment func (dc *LocalDockerCompose) WithEnv(env map[string]string) DockerCompose { dc.Env = env return dc } +// Deprecated: it will be removed in the next major release // WithExposedService sets the strategy for the service that is to be waited on. If multiple strategies // are given for a single service running on different ports, both strategies will be applied on the same container func (dc *LocalDockerCompose) WithExposedService(service string, port int, strategy wait.Strategy) DockerCompose { @@ -201,7 +217,8 @@ func (dc *LocalDockerCompose) WithExposedService(service string, port int, strat return dc } -// determineVersion checks which version of docker-compose is installed +// Deprecated: it will be removed in the next major release +// determineVersion checks which version of docker compose is installed // depending on the version services names are composed in a different way func (dc *LocalDockerCompose) determineVersion() error { execErr := executeCompose(dc, []string{"version", "--short"}) @@ -232,6 +249,7 @@ func (dc *LocalDockerCompose) determineVersion() error { return nil } +// Deprecated: it will be removed in the next major release // validate checks if the files to be run in the compose are valid YAML files, setting up // references to all services in them func (dc *LocalDockerCompose) validate() error { @@ -336,11 +354,12 @@ func execute( } } +// Deprecated: it will be removed in the next major release func executeCompose(dc *LocalDockerCompose, args []string) ExecError { if which(dc.Executable) != nil { return ExecError{ Command: []string{dc.Executable}, - Error: fmt.Errorf("Local Docker Compose not found. Is %s on the PATH?", dc.Executable), + Error: fmt.Errorf("Local Docker not found. Is %s on the PATH?", dc.Executable), } } @@ -349,7 +368,8 @@ func executeCompose(dc *LocalDockerCompose, args []string) ExecError { environment[k] = v } - var cmds []string + // initialise the command with the compose subcommand + cmds := []string{dc.composeSubcommand} pwd := "." if len(dc.absComposeFilePaths) > 0 { pwd, _ = filepath.Split(dc.absComposeFilePaths[0]) @@ -367,7 +387,7 @@ func executeCompose(dc *LocalDockerCompose, args []string) ExecError { if err != nil { args := strings.Join(dc.Cmd, " ") return ExecError{ - Command: []string{dc.Executable}, + Command: []string{dc.Executable, args}, Error: fmt.Errorf("Local Docker compose exited abnormally whilst running %s: [%v]. %s", dc.Executable, args, err.Error()), } } diff --git a/modules/compose/compose_test.go b/modules/compose/compose_test.go index bffec7bd94..c87e204725 100644 --- a/modules/compose/compose_test.go +++ b/modules/compose/compose_test.go @@ -33,7 +33,7 @@ func ExampleNewLocalDockerCompose() { func ExampleLocalDockerCompose() { _ = LocalDockerCompose{ - Executable: "docker-compose", + Executable: "docker compose", ComposeFilePaths: []string{ "/path/to/docker-compose.yml", "/path/to/docker-compose-1.yml",