Merge branch '3191_2_help_cli_feature' of https://github.com/twitherspoon/compose into 3191_2_help_cli_feature
This commit is contained in:
commit
f5b80640fe
35 changed files with 539 additions and 226 deletions
|
|
@ -6,6 +6,7 @@ import os
|
|||
import pytest
|
||||
|
||||
from compose.cli.command import get_config_path_from_options
|
||||
from compose.config.environment import Environment
|
||||
from compose.const import IS_WINDOWS_PLATFORM
|
||||
from tests import mock
|
||||
|
||||
|
|
@ -15,24 +16,33 @@ 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
|
||||
environment = Environment.from_env_file('.')
|
||||
assert get_config_path_from_options('.', opts, environment) == 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']
|
||||
environment = Environment.from_env_file('.')
|
||||
assert get_config_path_from_options('.', {}, environment) == ['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']
|
||||
environment = Environment.from_env_file('.')
|
||||
assert get_config_path_from_options(
|
||||
'.', {}, environment
|
||||
) == ['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']
|
||||
environment = Environment.from_env_file('.')
|
||||
assert get_config_path_from_options(
|
||||
'.', {}, environment
|
||||
) == ['one.yml', 'two.yml']
|
||||
|
||||
def test_no_path(self):
|
||||
assert not get_config_path_from_options({})
|
||||
environment = Environment.from_env_file('.')
|
||||
assert not get_config_path_from_options('.', {}, environment)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ class DockerClientTestCase(unittest.TestCase):
|
|||
def test_docker_client_no_home(self):
|
||||
with mock.patch.dict(os.environ):
|
||||
del os.environ['HOME']
|
||||
docker_client()
|
||||
docker_client(os.environ)
|
||||
|
||||
def test_docker_client_with_custom_timeout(self):
|
||||
timeout = 300
|
||||
with mock.patch('compose.cli.docker_client.HTTP_TIMEOUT', 300):
|
||||
client = docker_client()
|
||||
client = docker_client(os.environ)
|
||||
self.assertEqual(client.timeout, int(timeout))
|
||||
|
||||
|
||||
|
|
@ -103,3 +103,9 @@ class TLSConfigTestCase(unittest.TestCase):
|
|||
options = {'--tlskey': self.key}
|
||||
with pytest.raises(docker.errors.TLSParameterError):
|
||||
tls_config_from_options(options)
|
||||
|
||||
def test_assert_hostname_explicit_skip(self):
|
||||
options = {'--tlscacert': self.ca_cert, '--skip-hostname-check': True}
|
||||
result = tls_config_from_options(options)
|
||||
assert isinstance(result, docker.tls.TLSConfig)
|
||||
assert result.assert_hostname is False
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ from __future__ import absolute_import
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
import docker
|
||||
import py
|
||||
|
|
@ -43,11 +45,11 @@ class CLITestCase(unittest.TestCase):
|
|||
project_name = get_project_name(None, project_name=name)
|
||||
self.assertEquals('explicitprojectname', project_name)
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_project_name_from_environment_new_var(self):
|
||||
name = 'namefromenv'
|
||||
with mock.patch.dict(os.environ):
|
||||
os.environ['COMPOSE_PROJECT_NAME'] = name
|
||||
project_name = get_project_name(None)
|
||||
os.environ['COMPOSE_PROJECT_NAME'] = name
|
||||
project_name = get_project_name(None)
|
||||
self.assertEquals(project_name, name)
|
||||
|
||||
def test_project_name_with_empty_environment_var(self):
|
||||
|
|
@ -57,6 +59,22 @@ class CLITestCase(unittest.TestCase):
|
|||
project_name = get_project_name(base_dir)
|
||||
self.assertEquals('simplecomposefile', project_name)
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_project_name_with_environment_file(self):
|
||||
base_dir = tempfile.mkdtemp()
|
||||
try:
|
||||
name = 'namefromenvfile'
|
||||
with open(os.path.join(base_dir, '.env'), 'w') as f:
|
||||
f.write('COMPOSE_PROJECT_NAME={}'.format(name))
|
||||
project_name = get_project_name(base_dir)
|
||||
assert project_name == name
|
||||
|
||||
# Environment has priority over .env file
|
||||
os.environ['COMPOSE_PROJECT_NAME'] = 'namefromenv'
|
||||
assert get_project_name(base_dir) == os.environ['COMPOSE_PROJECT_NAME']
|
||||
finally:
|
||||
shutil.rmtree(base_dir)
|
||||
|
||||
def test_get_project(self):
|
||||
base_dir = 'tests/fixtures/longer-filename-composefile'
|
||||
project = get_project(base_dir)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from compose.config.config import resolve_build_args
|
|||
from compose.config.config import resolve_environment
|
||||
from compose.config.config import V1
|
||||
from compose.config.config import V2_0
|
||||
from compose.config.environment import Environment
|
||||
from compose.config.errors import ConfigurationError
|
||||
from compose.config.errors import VERSION_EXPLANATION
|
||||
from compose.config.types import VolumeSpec
|
||||
|
|
@ -36,7 +37,9 @@ def make_service_dict(name, service_dict, working_dir, filename=None):
|
|||
filename=filename,
|
||||
name=name,
|
||||
config=service_dict),
|
||||
config.ConfigFile(filename=filename, config={}))
|
||||
config.ConfigFile(filename=filename, config={}),
|
||||
environment=Environment.from_env_file(working_dir)
|
||||
)
|
||||
return config.process_service(resolver.run())
|
||||
|
||||
|
||||
|
|
@ -1581,8 +1584,25 @@ class PortsTest(unittest.TestCase):
|
|||
|
||||
|
||||
class InterpolationTest(unittest.TestCase):
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_config_file_with_environment_file(self):
|
||||
project_dir = 'tests/fixtures/default-env-file'
|
||||
service_dicts = config.load(
|
||||
config.find(
|
||||
project_dir, None, Environment.from_env_file(project_dir)
|
||||
)
|
||||
).services
|
||||
|
||||
self.assertEqual(service_dicts[0], {
|
||||
'name': 'web',
|
||||
'image': 'alpine:latest',
|
||||
'ports': ['5643', '9999'],
|
||||
'command': 'true'
|
||||
})
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_config_file_with_environment_variable(self):
|
||||
project_dir = 'tests/fixtures/environment-interpolation'
|
||||
os.environ.update(
|
||||
IMAGE="busybox",
|
||||
HOST_PORT="80",
|
||||
|
|
@ -1590,7 +1610,9 @@ class InterpolationTest(unittest.TestCase):
|
|||
)
|
||||
|
||||
service_dicts = config.load(
|
||||
config.find('tests/fixtures/environment-interpolation', None),
|
||||
config.find(
|
||||
project_dir, None, Environment.from_env_file(project_dir)
|
||||
)
|
||||
).services
|
||||
|
||||
self.assertEqual(service_dicts, [
|
||||
|
|
@ -1620,7 +1642,7 @@ class InterpolationTest(unittest.TestCase):
|
|||
None,
|
||||
)
|
||||
|
||||
with mock.patch('compose.config.interpolation.log') as log:
|
||||
with mock.patch('compose.config.environment.log') as log:
|
||||
config.load(config_details)
|
||||
|
||||
self.assertEqual(2, log.warn.call_count)
|
||||
|
|
@ -2041,7 +2063,9 @@ class EnvTest(unittest.TestCase):
|
|||
},
|
||||
}
|
||||
self.assertEqual(
|
||||
resolve_environment(service_dict),
|
||||
resolve_environment(
|
||||
service_dict, Environment.from_env_file(None)
|
||||
),
|
||||
{'FILE_DEF': 'F1', 'FILE_DEF_EMPTY': '', 'ENV_DEF': 'E3', 'NO_DEF': None},
|
||||
)
|
||||
|
||||
|
|
@ -2078,7 +2102,10 @@ class EnvTest(unittest.TestCase):
|
|||
os.environ['FILE_DEF_EMPTY'] = 'E2'
|
||||
os.environ['ENV_DEF'] = 'E3'
|
||||
self.assertEqual(
|
||||
resolve_environment({'env_file': ['tests/fixtures/env/resolve.env']}),
|
||||
resolve_environment(
|
||||
{'env_file': ['tests/fixtures/env/resolve.env']},
|
||||
Environment.from_env_file(None)
|
||||
),
|
||||
{
|
||||
'FILE_DEF': u'bär',
|
||||
'FILE_DEF_EMPTY': '',
|
||||
|
|
@ -2101,7 +2128,7 @@ class EnvTest(unittest.TestCase):
|
|||
}
|
||||
}
|
||||
self.assertEqual(
|
||||
resolve_build_args(build),
|
||||
resolve_build_args(build, Environment.from_env_file(build['context'])),
|
||||
{'arg1': 'value1', 'empty_arg': '', 'env_arg': 'value2', 'no_env': None},
|
||||
)
|
||||
|
||||
|
|
@ -2133,7 +2160,9 @@ class EnvTest(unittest.TestCase):
|
|||
|
||||
|
||||
def load_from_filename(filename):
|
||||
return config.load(config.find('.', [filename])).services
|
||||
return config.load(
|
||||
config.find('.', [filename], Environment.from_env_file('.'))
|
||||
).services
|
||||
|
||||
|
||||
class ExtendsTest(unittest.TestCase):
|
||||
|
|
@ -2465,6 +2494,7 @@ class ExtendsTest(unittest.TestCase):
|
|||
},
|
||||
]))
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_extends_with_environment_and_env_files(self):
|
||||
tmpdir = py.test.ensuretemp('test_extends_with_environment')
|
||||
self.addCleanup(tmpdir.remove)
|
||||
|
|
@ -2520,12 +2550,12 @@ class ExtendsTest(unittest.TestCase):
|
|||
},
|
||||
},
|
||||
]
|
||||
with mock.patch.dict(os.environ):
|
||||
os.environ['SECRET'] = 'secret'
|
||||
os.environ['THING'] = 'thing'
|
||||
os.environ['COMMON_ENV_FILE'] = 'secret'
|
||||
os.environ['TOP_ENV_FILE'] = 'secret'
|
||||
config = load_from_filename(str(tmpdir.join('docker-compose.yml')))
|
||||
|
||||
os.environ['SECRET'] = 'secret'
|
||||
os.environ['THING'] = 'thing'
|
||||
os.environ['COMMON_ENV_FILE'] = 'secret'
|
||||
os.environ['TOP_ENV_FILE'] = 'secret'
|
||||
config = load_from_filename(str(tmpdir.join('docker-compose.yml')))
|
||||
|
||||
assert config == expected
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import os
|
|||
import mock
|
||||
import pytest
|
||||
|
||||
from compose.config.environment import Environment
|
||||
from compose.config.interpolation import interpolate_environment_variables
|
||||
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ def mock_env():
|
|||
|
||||
def test_interpolate_environment_variables_in_services(mock_env):
|
||||
services = {
|
||||
'servivea': {
|
||||
'servicea': {
|
||||
'image': 'example:${USER}',
|
||||
'volumes': ['$FOO:/target'],
|
||||
'logging': {
|
||||
|
|
@ -31,7 +32,7 @@ def test_interpolate_environment_variables_in_services(mock_env):
|
|||
}
|
||||
}
|
||||
expected = {
|
||||
'servivea': {
|
||||
'servicea': {
|
||||
'image': 'example:jenny',
|
||||
'volumes': ['bar:/target'],
|
||||
'logging': {
|
||||
|
|
@ -42,7 +43,9 @@ def test_interpolate_environment_variables_in_services(mock_env):
|
|||
}
|
||||
}
|
||||
}
|
||||
assert interpolate_environment_variables(services, 'service') == expected
|
||||
assert interpolate_environment_variables(
|
||||
services, 'service', Environment.from_env_file(None)
|
||||
) == expected
|
||||
|
||||
|
||||
def test_interpolate_environment_variables_in_volumes(mock_env):
|
||||
|
|
@ -66,4 +69,6 @@ def test_interpolate_environment_variables_in_volumes(mock_env):
|
|||
},
|
||||
'other': {},
|
||||
}
|
||||
assert interpolate_environment_variables(volumes, 'volume') == expected
|
||||
assert interpolate_environment_variables(
|
||||
volumes, 'volume', Environment.from_env_file(None)
|
||||
) == expected
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import unittest
|
||||
|
||||
from compose.config.interpolation import BlankDefaultDict as bddict
|
||||
from compose.config.environment import Environment as bddict
|
||||
from compose.config.interpolation import interpolate
|
||||
from compose.config.interpolation import InvalidInterpolation
|
||||
|
||||
|
|
|
|||
|
|
@ -270,12 +270,21 @@ class ProjectTest(unittest.TestCase):
|
|||
'time': 1420092061,
|
||||
'timeNano': 14200920610000004000,
|
||||
},
|
||||
{
|
||||
'status': 'destroy',
|
||||
'from': 'example/db',
|
||||
'id': 'eeeee',
|
||||
'time': 1420092061,
|
||||
'timeNano': 14200920610000004000,
|
||||
},
|
||||
])
|
||||
|
||||
def dt_with_microseconds(dt, us):
|
||||
return datetime.datetime.fromtimestamp(dt).replace(microsecond=us)
|
||||
|
||||
def get_container(cid):
|
||||
if cid == 'eeeee':
|
||||
raise NotFound(None, None, "oops")
|
||||
if cid == 'abcde':
|
||||
name = 'web'
|
||||
labels = {LABEL_SERVICE: name}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue