Skip to content

Commit

Permalink
✨ Make docker.compose.down accept an optional list of service names (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
MisterOwlPT authored Mar 24, 2024
1 parent a8714e4 commit 32770a1
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 2 deletions.
12 changes: 12 additions & 0 deletions python_on_whales/components/compose/cli_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ def create(
@overload
def down(
self,
services: Union[List[str], str, None] = ...,
remove_orphans: bool = ...,
remove_images: Optional[str] = ...,
timeout: Optional[int] = ...,
Expand All @@ -229,6 +230,7 @@ def down(
@overload
def down(
self,
services: Union[List[str], str, None] = ...,
remove_orphans: bool = ...,
remove_images: Optional[str] = ...,
timeout: Optional[int] = ...,
Expand All @@ -240,6 +242,7 @@ def down(

def down(
self,
services: Union[List[str], str, None] = None,
remove_orphans: bool = False,
remove_images: Optional[str] = None,
timeout: Optional[int] = None,
Expand All @@ -250,6 +253,9 @@ def down(
"""Stops and removes the containers
Parameters:
services: The services to stop. If `None` (default), all services are
stopped. If an empty list is provided, the function call does nothing, it's
a no-op.
remove_orphans: Remove containers for services not defined in
the Compose file.
remove_images: Remove images used by services.
Expand All @@ -274,6 +280,12 @@ def down(
full_cmd.add_simple_arg("--timeout", timeout)
full_cmd.add_flag("--volumes", volumes)

if services == []:
return
elif services is not None:
services = to_list(services)
full_cmd += services

if stream_logs:
return stream_stdout_and_stderr(full_cmd)
else:
Expand Down
2 changes: 1 addition & 1 deletion scripts/download-docker-plugins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -e

mkdir -p ~/.docker/cli-plugins/
wget -q https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64 -O ~/.docker/cli-plugins/docker-compose
wget -q https://github.com/docker/compose/releases/download/v2.26.0/docker-compose-linux-x86_64 -O ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
wget -q https://github.com/docker/buildx/releases/download/v0.10.0/buildx-v0.10.0.linux-amd64 -O ~/.docker/cli-plugins/docker-buildx
chmod +x ~/.docker/cli-plugins/docker-buildx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "3.7"

services:

busybox:
container_name: busybox
image: busybox:latest
command: sleep infinity

alpine:
container_name: alpine
image: alpine:latest
command: sleep infinity
environment:
- DD_API_KEY=__your_datadog_api_key_here__
- POSTGRES_HOST_AUTH_METHOD=trust

dodo:
image: busybox:latest
entrypoint: /bin/sh
92 changes: 91 additions & 1 deletion tests/python_on_whales/components/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import datetime, timedelta
from os import makedirs, remove
from pathlib import Path
from unittest.mock import Mock, patch

import pytest
import pytz
Expand Down Expand Up @@ -186,6 +187,93 @@ def test_docker_compose_up_down_streaming():
assert b"Container components_alpine_1" in logs_as_big_binary


def test_docker_compose_down_services():
docker = DockerClient(
compose_files=[
PROJECT_ROOT
/ "tests/python_on_whales/components/dummy_compose_with_container_names.yml"
],
compose_compatibility=True,
compose_project_name="test_docker_compose_down_services",
)

docker.compose.up(["busybox", "alpine"], detach=True)
assert len(docker.compose.ps()) == 2

output_of_down = docker.compose.down(services=["busybox"])
assert output_of_down is None
assert len(docker.compose.ps()) == 1
active_container = docker.compose.ps()[0]
assert (
active_container.name == "alpine"
), f"actual container name: {active_container.name}"

output_of_down = docker.compose.down(services=["alpine"])
assert output_of_down is None
assert docker.compose.ps() == []


def test_docker_compose_down_no_services():
docker = DockerClient(
compose_files=[
PROJECT_ROOT
/ "tests/python_on_whales/components/dummy_compose_with_container_names.yml"
],
compose_compatibility=True,
compose_project_name="test_docker_compose_down_no_services",
)
docker.compose.up(["busybox", "alpine"], detach=True)
initial_containers = docker.compose.ps()
assert len(initial_containers) == 2

output_of_down = docker.compose.down(services=[])
assert output_of_down is None
final_containers = docker.compose.ps()
assert final_containers == initial_containers

output_of_down = docker.compose.down()
assert output_of_down is None
assert docker.compose.ps() == []


@patch("python_on_whales.components.compose.cli_wrapper.run")
def test_docker_compose_cli_down_all_services(run_mock: Mock):
docker.compose.down()
run_mock.assert_called_once_with(
docker.client_config.docker_compose_cmd + ["down"],
capture_stderr=False,
capture_stdout=False,
)


@patch("python_on_whales.components.compose.cli_wrapper.run")
def test_docker_compose_cli_down_multiple_services(run_mock: Mock):
test_services = ["test_a", "test_b"]
docker.compose.down(services=test_services)
run_mock.assert_called_once_with(
docker.client_config.docker_compose_cmd + ["down"] + test_services,
capture_stderr=False,
capture_stdout=False,
)


@patch("python_on_whales.components.compose.cli_wrapper.run")
def test_docker_compose_cli_down_single_service(run_mock: Mock):
test_service = "test_a"
docker.compose.down(services=test_service)
run_mock.assert_called_once_with(
docker.client_config.docker_compose_cmd + ["down"] + [test_service],
capture_stderr=False,
capture_stdout=False,
)


@patch("python_on_whales.components.compose.cli_wrapper.run")
def test_docker_compose_cli_down_services_no_op(run_mock: Mock):
docker.compose.down(services=[])
run_mock.assert_not_called()


def test_no_containers():
assert docker.compose.ps() == []

Expand Down Expand Up @@ -563,7 +651,9 @@ def test_config_complexe_compose():
docker = DockerClient(compose_files=[compose_file], compose_compatibility=True)
config = docker.compose.config()

assert config.services["my_service"].build.context == Path("my_service_build")
assert config.services["my_service"].build.context == (
PROJECT_ROOT / "tests/python_on_whales/components/my_service_build"
)
assert config.services["my_service"].image == "some_random_image"
assert config.services["my_service"].command == [
"ping",
Expand Down

0 comments on commit 32770a1

Please sign in to comment.