diff --git a/compose/cli/command.py b/compose/cli/command.py index 2a0d86984..98de21044 100644 --- a/compose/cli/command.py +++ b/compose/cli/command.py @@ -58,8 +58,10 @@ def get_config_path_from_options(options): if file_option: return file_option - config_file = os.environ.get('COMPOSE_FILE') - return [config_file] if config_file else None + config_files = os.environ.get('COMPOSE_FILE') + if config_files: + return config_files.split(os.pathsep) + return None def get_client(verbose=False, version=None): diff --git a/docs/reference/envvars.md b/docs/reference/envvars.md index 6360fe54a..e1170be90 100644 --- a/docs/reference/envvars.md +++ b/docs/reference/envvars.md @@ -27,10 +27,15 @@ defaults to the `basename` of the project directory. See also the `-p` ## COMPOSE\_FILE -Specify the file containing the compose configuration. If not provided, -Compose looks for a file named `docker-compose.yml` in the current directory -and then each parent directory in succession until a file by that name is -found. See also the `-f` [command-line option](overview.md). +Specify the path to a Compose file. If not provided, Compose looks for a file named +`docker-compose.yml` in the current directory and then each parent directory in +succession until a file by that name is found. + +This variable supports multiple compose files separate by a path separator (on +Linux and OSX the path separator is `:`, on Windows it is `;`). For example: +`COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml` + +See also the `-f` [command-line option](overview.md). ## COMPOSE\_API\_VERSION diff --git a/tests/unit/cli/command_test.py b/tests/unit/cli/command_test.py index 180446721..1ca671fed 100644 --- a/tests/unit/cli/command_test.py +++ b/tests/unit/cli/command_test.py @@ -1,16 +1,19 @@ from __future__ import absolute_import from __future__ import unicode_literals +import os + import pytest from requests.exceptions import ConnectionError from compose.cli import errors from compose.cli.command import friendly_error_message +from compose.cli.command import get_config_path_from_options +from compose.const import IS_WINDOWS_PLATFORM from tests import mock -from tests import unittest -class FriendlyErrorMessageTestCase(unittest.TestCase): +class TestFriendlyErrorMessage(object): def test_dispatch_generic_connection_error(self): with pytest.raises(errors.ConnectionErrorGeneric): @@ -21,3 +24,31 @@ class FriendlyErrorMessageTestCase(unittest.TestCase): ): with friendly_error_message(): raise ConnectionError() + + +class TestGetConfigPathFromOptions(object): + + def test_path_from_options(self): + paths = ['one.yml', 'two.yml'] + opts = {'--file': paths} + assert get_config_path_from_options(opts) == paths + + def test_single_path_from_env(self): + with mock.patch.dict(os.environ): + os.environ['COMPOSE_FILE'] = 'one.yml' + assert get_config_path_from_options({}) == ['one.yml'] + + @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix separator') + def test_multiple_path_from_env(self): + with mock.patch.dict(os.environ): + os.environ['COMPOSE_FILE'] = 'one.yml:two.yml' + assert get_config_path_from_options({}) == ['one.yml', 'two.yml'] + + @pytest.mark.skipif(not IS_WINDOWS_PLATFORM, reason='windows separator') + def test_multiple_path_from_env_windows(self): + with mock.patch.dict(os.environ): + os.environ['COMPOSE_FILE'] = 'one.yml;two.yml' + assert get_config_path_from_options({}) == ['one.yml', 'two.yml'] + + def test_no_path(self): + assert not get_config_path_from_options({})