From c594cb3fc38d3d80446cabf8c261d657a28c63c9 Mon Sep 17 00:00:00 2001 From: aiordache Date: Fri, 26 Feb 2021 10:38:59 +0100 Subject: [PATCH 1/9] Update changelog post-release 1.28.5 Signed-off-by: aiordache --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b9f0a96e..f0bacf36e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ Change log ========== +1.28.5 (2021-02-25) +------------------- + +[List of PRs / issues for this release](https://github.com/docker/compose/milestone/55?closed=1) + +### Bugs + +- Fix OpenSSL version mismatch error when shelling out to the ssh client (via bump to docker-py 4.4.4 which contains the fix) + +- Add missing build flags to the native builder: `platform`, `isolation` and `extra_hosts` + +- Remove info message on native build + +- Avoid fetching logs when service logging driver is set to 'none' + 1.28.4 (2021-02-18) ------------------- From 1da43016507dafb1823d8732d9a99be7abf9739c Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Mon, 1 Mar 2021 19:23:03 -0300 Subject: [PATCH 2/9] Advertise `docker compose` for non linux users This adds messages on: - Root command (only `docker-compose`) - Command not found - `help` command Signed-off-by: Ulysses Souza --- compose/cli/main.py | 12 ++++++++++++ compose/const.py | 1 + tox.ini | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compose/cli/main.py b/compose/cli/main.py index 494e85620..33c2ba8c9 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -23,6 +23,7 @@ from ..config import resolve_build_args from ..config.environment import Environment from ..config.serialize import serialize_config from ..config.types import VolumeSpec +from ..const import IS_LINUX_PLATFORM from ..const import IS_WINDOWS_PLATFORM from ..errors import StreamParseError from ..metrics.decorator import metrics @@ -78,6 +79,8 @@ def main(): # noqa: C901 try: command_func = dispatch() command_func() + if not IS_LINUX_PLATFORM and command == 'help': + print("\nDocker Compose is now in the Docker CLI, try `docker compose` help") except (KeyboardInterrupt, signals.ShutdownException): exit_with_metrics(command, "Aborting.", status=Status.FAILURE) except (UserError, NoSuchService, ConfigurationError, @@ -98,6 +101,8 @@ def main(): # noqa: C901 e.service.name), status=Status.FAILURE) except NoSuchCommand as e: commands = "\n".join(parse_doc_section("commands:", getdoc(e.supercommand))) + if not IS_LINUX_PLATFORM: + commands += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`" exit_with_metrics(e.command, "No such command: {}\n\n{}".format(e.command, commands)) except (errors.ConnectionError, StreamParseError): exit_with_metrics(command, status=Status.FAILURE) @@ -116,6 +121,10 @@ def main(): # noqa: C901 code = 0 if isinstance(e.code, int): code = e.code + + if not IS_LINUX_PLATFORM and not command: + msg += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`" + exit_with_metrics(command, log_msg=msg, status=status, exit_code=code) @@ -1123,6 +1132,9 @@ class TopLevelCommand: attach_dependencies = options.get('--attach-dependencies') keep_prefix = not options.get('--no-log-prefix') + if not IS_LINUX_PLATFORM: + print('Docker Compose is now in the Docker CLI, try `docker compose up`\n') + 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.") diff --git a/compose/const.py b/compose/const.py index 043429802..90cd38e82 100644 --- a/compose/const.py +++ b/compose/const.py @@ -5,6 +5,7 @@ from .version import ComposeVersion DEFAULT_TIMEOUT = 10 HTTP_TIMEOUT = 60 IS_WINDOWS_PLATFORM = (sys.platform == "win32") +IS_LINUX_PLATFORM = (sys.platform == "linux") LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number' LABEL_ONE_OFF = 'com.docker.compose.oneoff' LABEL_PROJECT = 'com.docker.compose.project' diff --git a/tox.ini b/tox.ini index 80b6e256d..12530d191 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ directory = coverage-html [flake8] max-line-length = 105 # Set this high for now -max-complexity = 11 +max-complexity = 12 exclude = compose/packages [pytest] From 2a7c06a050727b6dfe4d12f01a738a9926a22da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 6 Mar 2021 18:45:59 +0100 Subject: [PATCH 3/9] Use built-in functools.cached_property when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cached_property decorator is built-in in functools module since Python 3.8. Use the external cached_property package only for older versions of Python. Signed-off-by: Michał Górny --- compose/config/config.py | 6 +++++- requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compose/config/config.py b/compose/config/config.py index 39c815a98..6cc55a06f 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -10,7 +10,11 @@ from operator import attrgetter from operator import itemgetter import yaml -from cached_property import cached_property + +try: + from functools import cached_property +except ImportError: + from cached_property import cached_property from . import types from ..const import COMPOSE_SPEC as VERSION diff --git a/requirements.txt b/requirements.txt index a7f0e0279..13923a7f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ backports.shutil_get_terminal_size==1.0.0 -cached-property==1.5.1 +cached-property==1.5.1; python_version < '3.8' certifi==2020.6.20 chardet==3.0.4 colorama==0.4.3; sys_platform == 'win32' diff --git a/setup.py b/setup.py index c58a1acc4..766997907 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ def find_version(*file_paths): install_requires = [ - 'cached-property >= 1.2.0, < 2', 'docopt >= 0.6.1, < 1', 'PyYAML >= 3.10, < 6', 'requests >= 2.20.0, < 3', @@ -50,6 +49,7 @@ if sys.version_info[:2] < (3, 4): extras_require = { ':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5, < 4'], + ':python_version < "3.8"': ['cached-property >= 1.2.0, < 2'], ':sys_platform == "win32"': ['colorama >= 0.4, < 1'], 'socks': ['PySocks >= 1.5.6, != 1.5.7, < 2'], 'tests': tests_require, From 3e071ec8d96c04a033c467a3d06bad192cb89d8a Mon Sep 17 00:00:00 2001 From: Anca Iordache Date: Tue, 9 Mar 2021 18:28:36 +0100 Subject: [PATCH 4/9] Fix build.extra_hosts list format Signed-off-by: Anca Iordache --- compose/service.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compose/service.py b/compose/service.py index 3829e8269..53cf42ae8 100644 --- a/compose/service.py +++ b/compose/service.py @@ -1877,8 +1877,10 @@ class _CLIBuilder: command_builder.add_arg("--isolation", isolation) if extra_hosts: - for host, ip in extra_hosts.items(): - command_builder.add_arg("--add-host", "{}:{}".format(host, ip)) + if isinstance(extra_hosts, dict): + extra_hosts = ["{}:{}".format(host, ip) for host, ip in extra_hosts.items()] + for host in extra_hosts: + command_builder.add_arg("--add-host", "{}".format(host)) args = command_builder.build([path]) From eaa22df15174f90d62421fe175f1999ffa430bfd Mon Sep 17 00:00:00 2001 From: Anca Iordache Date: Tue, 9 Mar 2021 19:21:08 +0100 Subject: [PATCH 5/9] Do not use context as base dir for Dockerfile when context is a git url Signed-off-by: Anca Iordache --- compose/service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose/service.py b/compose/service.py index 3829e8269..c8e268438 100644 --- a/compose/service.py +++ b/compose/service.py @@ -1855,7 +1855,7 @@ class _CLIBuilder: Returns: A generator for the build output. """ - if dockerfile: + if dockerfile and os.path.isdir(path): dockerfile = os.path.join(path, dockerfile) iidfile = tempfile.mktemp() From 4a26d95de466560811806790bba93cbf739883af Mon Sep 17 00:00:00 2001 From: Anca Iordache Date: Fri, 12 Mar 2021 11:47:26 +0100 Subject: [PATCH 6/9] Make `--env-file` paths relative to current working directory Look up compose files in project dir as fallback to no compose file in current working directory Update config and env-file tests - get_default_config does not raise error anymore, returns None if no compose file is found Signed-off-by: Anca Iordache --- compose/config/config.py | 14 +++++++++++--- compose/config/environment.py | 7 ++++--- tests/fixtures/env-file-override/.env | 1 + tests/integration/environment_test.py | 28 ++++++++++++++++++++++++++- tests/unit/config/config_test.py | 10 +++++++--- 5 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 tests/fixtures/env-file-override/.env diff --git a/compose/config/config.py b/compose/config/config.py index 39c815a98..cd708bae3 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -304,7 +304,16 @@ def find(base_dir, filenames, environment, override_dir=None): if filenames: filenames = [os.path.join(base_dir, f) for f in filenames] else: + # search for compose files in the base dir and its parents filenames = get_default_config_files(base_dir) + if not filenames and not override_dir: + # none found in base_dir and no override_dir defined + raise ComposeFileNotFound(SUPPORTED_FILENAMES) + if not filenames: + # search for compose files in the project directory and its parents + filenames = get_default_config_files(override_dir) + if not filenames: + raise ComposeFileNotFound(SUPPORTED_FILENAMES) log.debug("Using configuration files: {}".format(",".join(filenames))) return ConfigDetails( @@ -335,7 +344,7 @@ def get_default_config_files(base_dir): (candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, base_dir) if not candidates: - raise ComposeFileNotFound(SUPPORTED_FILENAMES) + return None winner = candidates[0] @@ -556,8 +565,7 @@ def process_config_section(config_file, config, section, environment, interpolat config_file.version, config, section, - environment - ) + environment) else: return config diff --git a/compose/config/environment.py b/compose/config/environment.py index 8769df9f8..5045a730b 100644 --- a/compose/config/environment.py +++ b/compose/config/environment.py @@ -54,9 +54,10 @@ class Environment(dict): if base_dir is None: return result if env_file: - env_file_path = os.path.join(base_dir, env_file) - else: - env_file_path = os.path.join(base_dir, '.env') + env_file_path = os.path.join(os.getcwd(), env_file) + return cls(env_vars_from_file(env_file_path)) + + env_file_path = os.path.join(base_dir, '.env') try: return cls(env_vars_from_file(env_file_path)) except EnvFileNotFound: diff --git a/tests/fixtures/env-file-override/.env b/tests/fixtures/env-file-override/.env new file mode 100644 index 000000000..467f2c1d2 --- /dev/null +++ b/tests/fixtures/env-file-override/.env @@ -0,0 +1 @@ +WHEREAMI=default diff --git a/tests/integration/environment_test.py b/tests/integration/environment_test.py index 12a969c94..92e12e0d4 100644 --- a/tests/integration/environment_test.py +++ b/tests/integration/environment_test.py @@ -3,11 +3,14 @@ import tempfile from ddt import data from ddt import ddt +import pytest + from .. import mock from ..acceptance.cli_test import dispatch from compose.cli.command import get_project from compose.cli.command import project_from_options from compose.config.environment import Environment +from compose.config.errors import EnvFileNotFound from tests.integration.testcases import DockerClientTestCase @@ -55,13 +58,36 @@ services: class EnvironmentOverrideFileTest(DockerClientTestCase): def test_env_file_override(self): base_dir = 'tests/fixtures/env-file-override' + # '--env-file' are relative to the current working dir + env = Environment.from_env_file(base_dir, base_dir+'/.env.override') dispatch(base_dir, ['--env-file', '.env.override', 'up']) project = get_project(project_dir=base_dir, config_path=['docker-compose.yml'], - environment=Environment.from_env_file(base_dir, '.env.override'), + environment=env, override_dir=base_dir) containers = project.containers(stopped=True) assert len(containers) == 1 assert "WHEREAMI=override" in containers[0].get('Config.Env') assert "DEFAULT_CONF_LOADED=true" in containers[0].get('Config.Env') dispatch(base_dir, ['--env-file', '.env.override', 'down'], None) + + def test_env_file_not_found_error(self): + base_dir = 'tests/fixtures/env-file-override' + with pytest.raises(EnvFileNotFound) as excinfo: + Environment.from_env_file(base_dir, '.env.override') + + assert "Couldn't find env file" in excinfo.exconly() + + def test_dot_env_file(self): + base_dir = 'tests/fixtures/env-file-override' + # '.env' is relative to the project_dir (base_dir) + env = Environment.from_env_file(base_dir, None) + dispatch(base_dir, ['up']) + project = get_project(project_dir=base_dir, + config_path=['docker-compose.yml'], + environment=env, + override_dir=base_dir) + containers = project.containers(stopped=True) + assert len(containers) == 1 + assert "WHEREAMI=default" in containers[0].get('Config.Env') + dispatch(base_dir, ['down'], None) diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index ffc16e085..13a30e7bd 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -3567,9 +3567,11 @@ class InterpolationTest(unittest.TestCase): @mock.patch.dict(os.environ) def test_config_file_with_options_environment_file(self): project_dir = 'tests/fixtures/default-env-file' + # env-file is relative to current working dir + env = Environment.from_env_file(project_dir, project_dir + '/.env2') service_dicts = config.load( config.find( - project_dir, None, Environment.from_env_file(project_dir, '.env2') + project_dir, None, env ) ).services @@ -5266,8 +5268,10 @@ def get_config_filename_for_files(filenames, subdir=None): base_dir = tempfile.mkdtemp(dir=project_dir) else: base_dir = project_dir - filename, = config.get_default_config_files(base_dir) - return os.path.basename(filename) + filenames = config.get_default_config_files(base_dir) + if not filenames: + raise config.ComposeFileNotFound(config.SUPPORTED_FILENAMES) + return os.path.basename(filenames[0]) finally: shutil.rmtree(project_dir) From f5342b600c0c4bb8915f238212e66e57466b6bda Mon Sep 17 00:00:00 2001 From: Anca Iordache Date: Tue, 16 Mar 2021 11:27:22 +0100 Subject: [PATCH 7/9] Add `compose.yaml/.yml` to default filenames Signed-off-by: Anca Iordache --- compose/config/config.py | 7 ++++++- tests/integration/environment_test.py | 3 +-- tests/unit/config/config_test.py | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compose/config/config.py b/compose/config/config.py index cd708bae3..3fec40197 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -149,9 +149,14 @@ DOCKER_VALID_URL_PREFIXES = ( SUPPORTED_FILENAMES = [ 'docker-compose.yml', 'docker-compose.yaml', + 'compose.yml', + 'compose.yaml', ] -DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml', 'docker-compose.override.yaml') +DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml', + 'docker-compose.override.yaml', + 'compose.override.yml', + 'compose.override.yaml') log = logging.getLogger(__name__) diff --git a/tests/integration/environment_test.py b/tests/integration/environment_test.py index 92e12e0d4..b7822a594 100644 --- a/tests/integration/environment_test.py +++ b/tests/integration/environment_test.py @@ -1,10 +1,9 @@ import tempfile +import pytest from ddt import data from ddt import ddt -import pytest - from .. import mock from ..acceptance.cli_test import dispatch from compose.cli.command import get_project diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index 13a30e7bd..60b82dcf2 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -5235,6 +5235,8 @@ class GetDefaultConfigFilesTestCase(unittest.TestCase): files = [ 'docker-compose.yml', 'docker-compose.yaml', + 'compose.yml', + 'compose.yaml', ] def test_get_config_path_default_file_in_basedir(self): From 5ec8af582c4ea84e10960f888cf51973446d9185 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Wed, 17 Mar 2021 17:49:15 -0300 Subject: [PATCH 8/9] Fix on removing error message on 'exec' error Signed-off-by: Ulysses Souza --- compose/cli/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose/cli/main.py b/compose/cli/main.py index 33c2ba8c9..ea82dd116 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -137,7 +137,7 @@ def get_filtered_args(args): def exit_with_metrics(command, log_msg=None, status=Status.SUCCESS, exit_code=1): - if log_msg: + if log_msg and command != 'exec': if not exit_code: log.info(log_msg) else: From 8ce5e235e453169310f81794c74f5e83cd6ebc40 Mon Sep 17 00:00:00 2001 From: Anca Iordache Date: Mon, 22 Mar 2021 19:22:02 +0100 Subject: [PATCH 9/9] Add back `storage_opts` as service property Signed-off-by: Anca Iordache --- compose/config/compose_spec.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose/config/compose_spec.json b/compose/config/compose_spec.json index c0d483669..8eadb8f2f 100644 --- a/compose/config/compose_spec.json +++ b/compose/config/compose_spec.json @@ -335,7 +335,6 @@ "read_only": {"type": "boolean"}, "restart": {"type": "string"}, "runtime": { - "deprecated": true, "type": "string" }, "scale": { @@ -367,6 +366,7 @@ "stdin_open": {"type": "boolean"}, "stop_grace_period": {"type": "string", "format": "duration"}, "stop_signal": {"type": "string"}, + "storage_opt": {"type": "object"}, "tmpfs": {"$ref": "#/definitions/string_or_list"}, "tty": {"type": "boolean"}, "ulimits": {