Prechádzať zdrojové kódy

Merge pull request #6950 from benthorner/master

Add "--attach-dependencies" to command "up" for attaching to dependencies
Ulysses Souza 5 rokov pred
rodič
commit
f0e5926ea7

+ 12 - 6
compose/cli/main.py

@@ -1012,6 +1012,7 @@ class TopLevelCommand(object):
             --build                    Build images before starting containers.
             --abort-on-container-exit  Stops all containers if any container was
                                        stopped. Incompatible with -d.
+            --attach-dependencies      Attach to dependent containers
             -t, --timeout TIMEOUT      Use this timeout in seconds for container
                                        shutdown when attached or when containers are
                                        already running. (default: 10)
@@ -1033,16 +1034,18 @@ class TopLevelCommand(object):
         remove_orphans = options['--remove-orphans']
         detached = options.get('--detach')
         no_start = options.get('--no-start')
+        attach_dependencies = options.get('--attach-dependencies')
 
-        if detached and (cascade_stop or exit_value_from):
-            raise UserError("--abort-on-container-exit and -d cannot be combined.")
+        if detached and (cascade_stop or exit_value_from or attach_dependencies):
+            raise UserError(
+                "-d cannot be combined with --abort-on-container-exit or --attach-dependencies.")
 
         ignore_orphans = self.toplevel_environment.get_boolean('COMPOSE_IGNORE_ORPHANS')
 
         if ignore_orphans and remove_orphans:
             raise UserError("COMPOSE_IGNORE_ORPHANS and --remove-orphans cannot be combined.")
 
-        opts = ['--detach', '--abort-on-container-exit', '--exit-code-from']
+        opts = ['--detach', '--abort-on-container-exit', '--exit-code-from', '--attach-dependencies']
         for excluded in [x for x in opts if options.get(x) and no_start]:
             raise UserError('--no-start and {} cannot be combined.'.format(excluded))
 
@@ -1087,7 +1090,10 @@ class TopLevelCommand(object):
             if detached or no_start:
                 return
 
-            attached_containers = filter_containers_to_service_names(to_attach, service_names)
+            attached_containers = filter_attached_containers(
+                to_attach,
+                service_names,
+                attach_dependencies)
 
             log_printer = log_printer_from_project(
                 self.project,
@@ -1392,8 +1398,8 @@ def log_printer_from_project(
         log_args=log_args)
 
 
-def filter_containers_to_service_names(containers, service_names):
-    if not service_names:
+def filter_attached_containers(containers, service_names, attach_dependencies=False):
+    if attach_dependencies or not service_names:
         return containers
 
     return [

+ 1 - 1
contrib/completion/bash/docker-compose

@@ -545,7 +545,7 @@ _docker_compose_up() {
 
 	case "$cur" in
 		-*)
-			COMPREPLY=( $( compgen -W "--abort-on-container-exit --always-recreate-deps --build -d --detach --exit-code-from --force-recreate --help --no-build --no-color --no-deps --no-recreate --no-start --renew-anon-volumes -V --remove-orphans --scale --timeout -t" -- "$cur" ) )
+			COMPREPLY=( $( compgen -W "--abort-on-container-exit --always-recreate-deps --attach-dependencies --build -d --detach --exit-code-from --force-recreate --help --no-build --no-color --no-deps --no-recreate --no-start --renew-anon-volumes -V --remove-orphans --scale --timeout -t" -- "$cur" ) )
 			;;
 		*)
 			__docker_compose_complete_services

+ 2 - 1
contrib/completion/zsh/_docker-compose

@@ -284,7 +284,7 @@ __docker-compose_subcommand() {
         (up)
             _arguments \
                 $opts_help \
-                '(--abort-on-container-exit)-d[Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit.]' \
+                '(--abort-on-container-exit)-d[Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit and --attach-dependencies.]' \
                 $opts_no_color \
                 $opts_no_deps \
                 $opts_force_recreate \
@@ -292,6 +292,7 @@ __docker-compose_subcommand() {
                 $opts_no_build \
                 "(--no-build)--build[Build images before starting containers.]" \
                 "(-d)--abort-on-container-exit[Stops all containers if any container was stopped. Incompatible with -d.]" \
+                "(-d)--attach-dependencies[Attach to dependent containers. Incompatible with -d.]" \
                 '(-t --timeout)'{-t,--timeout}"[Use this timeout in seconds for container shutdown when attached or when containers are already running. (default: 10)]:seconds: " \
                 '--scale[SERVICE=NUM Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.]:service scale SERVICE=NUM: ' \
                 '--exit-code-from=[Return the exit code of the selected service container. Implies --abort-on-container-exit]:service:__docker-compose_services' \

+ 20 - 0
tests/acceptance/cli_test.py

@@ -1571,6 +1571,26 @@ services:
         assert len(db.containers()) == 0
         assert len(console.containers()) == 0
 
+    def test_up_with_attach_dependencies(self):
+        self.base_dir = 'tests/fixtures/echo-services-dependencies'
+        result = self.dispatch(['up', '--attach-dependencies', '--no-color', 'simple'], None)
+        simple_name = self.project.get_service('simple').containers(stopped=True)[0].name_without_project
+        another_name = self.project.get_service('another').containers(
+            stopped=True
+        )[0].name_without_project
+
+        assert '{}   | simple'.format(simple_name) in result.stdout
+        assert '{}  | another'.format(another_name) in result.stdout
+
+    def test_up_handles_aborted_dependencies(self):
+        self.base_dir = 'tests/fixtures/abort-on-container-exit-dependencies'
+        proc = start_process(
+            self.base_dir,
+            ['up', 'simple', '--attach-dependencies', '--abort-on-container-exit'])
+        wait_on_condition(ContainerCountCondition(self.project, 0))
+        proc.wait()
+        assert proc.returncode == 1
+
     def test_up_with_force_recreate(self):
         self.dispatch(['up', '-d'], None)
         service = self.project.get_service('simple')

+ 10 - 0
tests/fixtures/abort-on-container-exit-dependencies/docker-compose.yml

@@ -0,0 +1,10 @@
+version: "2.0"
+services:
+  simple:
+    image: busybox:1.31.0-uclibc
+    command: top
+    depends_on:
+      - another
+  another:
+    image: busybox:1.31.0-uclibc
+    command: ls /thecakeisalie

+ 10 - 0
tests/fixtures/echo-services-dependencies/docker-compose.yml

@@ -0,0 +1,10 @@
+version: "2.0"
+services:
+  simple:
+    image: busybox:1.31.0-uclibc
+    command: echo simple
+    depends_on:
+      - another
+  another:
+    image: busybox:1.31.0-uclibc
+    command: echo another

+ 17 - 5
tests/unit/cli/main_test.py

@@ -12,7 +12,7 @@ from compose.cli.formatter import ConsoleWarningFormatter
 from compose.cli.main import build_one_off_container_options
 from compose.cli.main import call_docker
 from compose.cli.main import convergence_strategy_from_opts
-from compose.cli.main import filter_containers_to_service_names
+from compose.cli.main import filter_attached_containers
 from compose.cli.main import get_docker_start_call
 from compose.cli.main import setup_console_handler
 from compose.cli.main import warn_for_swarm_mode
@@ -37,7 +37,7 @@ def logging_handler():
 
 class TestCLIMainTestCase(object):
 
-    def test_filter_containers_to_service_names(self):
+    def test_filter_attached_containers(self):
         containers = [
             mock_container('web', 1),
             mock_container('web', 2),
@@ -46,17 +46,29 @@ class TestCLIMainTestCase(object):
             mock_container('another', 1),
         ]
         service_names = ['web', 'db']
-        actual = filter_containers_to_service_names(containers, service_names)
+        actual = filter_attached_containers(containers, service_names)
         assert actual == containers[:3]
 
-    def test_filter_containers_to_service_names_all(self):
+    def test_filter_attached_containers_with_dependencies(self):
+        containers = [
+            mock_container('web', 1),
+            mock_container('web', 2),
+            mock_container('db', 1),
+            mock_container('other', 1),
+            mock_container('another', 1),
+        ]
+        service_names = ['web', 'db']
+        actual = filter_attached_containers(containers, service_names, attach_dependencies=True)
+        assert actual == containers
+
+    def test_filter_attached_containers_all(self):
         containers = [
             mock_container('web', 1),
             mock_container('db', 1),
             mock_container('other', 1),
         ]
         service_names = []
-        actual = filter_containers_to_service_names(containers, service_names)
+        actual = filter_attached_containers(containers, service_names)
         assert actual == containers
 
     def test_warning_in_swarm_mode(self):