diff --git a/pkg/compose/start.go b/pkg/compose/start.go index ff699ffb0..d1af0637c 100644 --- a/pkg/compose/start.go +++ b/pkg/compose/start.go @@ -80,7 +80,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options depends := types.DependsOnConfig{} for _, s := range project.Services { depends[s.Name] = types.ServiceDependency{ - Condition: ServiceConditionRunningOrHealthy, + Condition: getDependencyCondition(s, project), } } err = s.waitDependencies(ctx, project, depends) @@ -92,6 +92,20 @@ func (s *composeService) start(ctx context.Context, projectName string, options return eg.Wait() } +// getDependencyCondition checks if service is depended on by other services +// with service_completed_successfully condition, and applies that condition +// instead, or --wait will never finish waiting for one-shot containers +func getDependencyCondition(service types.ServiceConfig, project *types.Project) string { + for _, services := range project.Services { + for dependencyService, dependencyConfig := range services.DependsOn { + if dependencyService == service.Name && dependencyConfig.Condition == types.ServiceConditionCompletedSuccessfully { + return types.ServiceConditionCompletedSuccessfully + } + } + } + return ServiceConditionRunningOrHealthy +} + type containerWatchFn func(container moby.Container) error // watchContainers uses engine events to capture container start/die and notify ContainerEventListener diff --git a/pkg/e2e/compose_up_test.go b/pkg/e2e/compose_up_test.go new file mode 100644 index 000000000..f96e7f0b7 --- /dev/null +++ b/pkg/e2e/compose_up_test.go @@ -0,0 +1,47 @@ +/* + Copyright 2020 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package e2e + +import ( + "strings" + "testing" + "time" + + "gotest.tools/v3/assert" +) + +func TestUpWait(t *testing.T) { + c := NewParallelCLI(t) + const projectName = "e2e-deps-wait" + + timeout := time.After(30 * time.Second) + done := make(chan bool) + go func() { + res := c.RunDockerComposeCmd(t, "-f", "fixtures/dependencies/deps-completed-successfully.yaml", "--project-name", projectName, "up", "--wait", "-d") + assert.Assert(t, strings.Contains(res.Combined(), "e2e-deps-wait-oneshot-1"), res.Combined()) + done <- true + }() + + select { + case <-timeout: + t.Fatal("test did not finish in time") + case <-done: + break + } + + c.RunDockerComposeCmd(t, "--project-name", projectName, "down") +} diff --git a/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml b/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml new file mode 100644 index 000000000..1acd08735 --- /dev/null +++ b/pkg/e2e/fixtures/dependencies/deps-completed-successfully.yaml @@ -0,0 +1,11 @@ +version: '3' +services: + oneshot: + image: ubuntu + command: echo 'hello world' + longrunning: + image: ubuntu + depends_on: + oneshot: + condition: service_completed_successfully + command: sleep infinity