Add support for build arguments
Allows 'build' configuration option to be specified as an object and adds support for build args. Signed-off-by: Garrett Heel <garrettheel@gmail.com>
This commit is contained in:
parent
77b4ebc31f
commit
9cfa71ceee
9 changed files with 297 additions and 49 deletions
|
|
@ -294,7 +294,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
project='composetest',
|
||||
name='db',
|
||||
client=self.client,
|
||||
build='tests/fixtures/dockerfile-with-volume',
|
||||
build={'context': 'tests/fixtures/dockerfile-with-volume'},
|
||||
)
|
||||
|
||||
old_container = create_and_start_container(service)
|
||||
|
|
@ -315,7 +315,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
def test_execute_convergence_plan_when_image_volume_masks_config(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
build='tests/fixtures/dockerfile-with-volume',
|
||||
build={'context': 'tests/fixtures/dockerfile-with-volume'},
|
||||
)
|
||||
|
||||
old_container = create_and_start_container(service)
|
||||
|
|
@ -346,7 +346,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
def test_execute_convergence_plan_without_start(self):
|
||||
service = self.create_service(
|
||||
'db',
|
||||
build='tests/fixtures/dockerfile-with-volume'
|
||||
build={'context': 'tests/fixtures/dockerfile-with-volume'}
|
||||
)
|
||||
|
||||
containers = service.execute_convergence_plan(ConvergencePlan('create', []), start=False)
|
||||
|
|
@ -450,7 +450,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
service = Service(
|
||||
name='test',
|
||||
client=self.client,
|
||||
build='tests/fixtures/simple-dockerfile',
|
||||
build={'context': 'tests/fixtures/simple-dockerfile'},
|
||||
project='composetest',
|
||||
)
|
||||
container = create_and_start_container(service)
|
||||
|
|
@ -463,7 +463,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
service = Service(
|
||||
name='test',
|
||||
client=self.client,
|
||||
build='this/does/not/exist/and/will/throw/error',
|
||||
build={'context': 'this/does/not/exist/and/will/throw/error'},
|
||||
project='composetest',
|
||||
)
|
||||
container = create_and_start_container(service)
|
||||
|
|
@ -483,7 +483,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f:
|
||||
f.write("FROM busybox\n")
|
||||
|
||||
self.create_service('web', build=base_dir).build()
|
||||
self.create_service('web', build={'context': base_dir}).build()
|
||||
assert self.client.inspect_image('composetest_web')
|
||||
|
||||
def test_build_non_ascii_filename(self):
|
||||
|
|
@ -496,7 +496,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
with open(os.path.join(base_dir.encode('utf8'), b'foo\xE2bar'), 'w') as f:
|
||||
f.write("hello world\n")
|
||||
|
||||
self.create_service('web', build=text_type(base_dir)).build()
|
||||
self.create_service('web', build={'context': text_type(base_dir)}).build()
|
||||
assert self.client.inspect_image('composetest_web')
|
||||
|
||||
def test_build_with_image_name(self):
|
||||
|
|
@ -508,16 +508,30 @@ class ServiceTest(DockerClientTestCase):
|
|||
|
||||
image_name = 'examples/composetest:latest'
|
||||
self.addCleanup(self.client.remove_image, image_name)
|
||||
self.create_service('web', build=base_dir, image=image_name).build()
|
||||
self.create_service('web', build={'context': base_dir}, image=image_name).build()
|
||||
assert self.client.inspect_image(image_name)
|
||||
|
||||
def test_build_with_git_url(self):
|
||||
build_url = "https://github.com/dnephin/docker-build-from-url.git"
|
||||
service = self.create_service('buildwithurl', build=build_url)
|
||||
service = self.create_service('buildwithurl', build={'context': build_url})
|
||||
self.addCleanup(self.client.remove_image, service.image_name)
|
||||
service.build()
|
||||
assert service.image()
|
||||
|
||||
def test_build_with_build_args(self):
|
||||
base_dir = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base_dir)
|
||||
|
||||
with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f:
|
||||
f.write("FROM busybox\n")
|
||||
f.write("ARG build_version\n")
|
||||
|
||||
service = self.create_service('buildwithargs',
|
||||
build={'context': text_type(base_dir),
|
||||
'args': {"build_version": "1"}})
|
||||
service.build()
|
||||
assert service.image()
|
||||
|
||||
def test_start_container_stays_unpriviliged(self):
|
||||
service = self.create_service('web')
|
||||
container = create_and_start_container(service).inspect()
|
||||
|
|
|
|||
|
|
@ -266,13 +266,13 @@ class ServiceStateTest(DockerClientTestCase):
|
|||
dockerfile = context.join('Dockerfile')
|
||||
dockerfile.write(base_image)
|
||||
|
||||
web = self.create_service('web', build=str(context))
|
||||
web = self.create_service('web', build={'context': str(context)})
|
||||
container = web.create_container()
|
||||
|
||||
dockerfile.write(base_image + 'CMD echo hello world\n')
|
||||
web.build()
|
||||
|
||||
web = self.create_service('web', build=str(context))
|
||||
web = self.create_service('web', build={'context': str(context)})
|
||||
self.assertEqual(('recreate', [container]), web.convergence_plan())
|
||||
|
||||
def test_image_changed_to_build(self):
|
||||
|
|
@ -286,7 +286,7 @@ class ServiceStateTest(DockerClientTestCase):
|
|||
web = self.create_service('web', image='busybox')
|
||||
container = web.create_container()
|
||||
|
||||
web = self.create_service('web', build=str(context))
|
||||
web = self.create_service('web', build={'context': str(context)})
|
||||
plan = web.convergence_plan()
|
||||
self.assertEqual(('recreate', [container]), plan)
|
||||
containers = web.execute_convergence_plan(plan)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import py
|
|||
import pytest
|
||||
|
||||
from compose.config import config
|
||||
from compose.config.config import resolve_build_args
|
||||
from compose.config.config import resolve_environment
|
||||
from compose.config.errors import ConfigurationError
|
||||
from compose.config.types import VolumeSpec
|
||||
|
|
@ -284,7 +285,7 @@ class ConfigTest(unittest.TestCase):
|
|||
expected = [
|
||||
{
|
||||
'name': 'web',
|
||||
'build': os.path.abspath('/'),
|
||||
'build': {'context': os.path.abspath('/')},
|
||||
'volumes': [VolumeSpec.parse('/home/user/project:/code')],
|
||||
'links': ['db'],
|
||||
},
|
||||
|
|
@ -414,6 +415,59 @@ class ConfigTest(unittest.TestCase):
|
|||
assert services[1]['name'] == 'db'
|
||||
assert services[2]['name'] == 'web'
|
||||
|
||||
def test_config_build_configuration(self):
|
||||
service = config.load(
|
||||
build_config_details(
|
||||
{'web': {
|
||||
'build': '.',
|
||||
'dockerfile': 'Dockerfile-alt'
|
||||
}},
|
||||
'tests/fixtures/extends',
|
||||
'filename.yml'
|
||||
)
|
||||
).services
|
||||
self.assertTrue('context' in service[0]['build'])
|
||||
self.assertEqual(service[0]['build']['dockerfile'], 'Dockerfile-alt')
|
||||
|
||||
def test_config_build_configuration_v2(self):
|
||||
service = config.load(
|
||||
build_config_details(
|
||||
{
|
||||
'version': 2,
|
||||
'services': {
|
||||
'web': {
|
||||
'build': '.',
|
||||
'dockerfile': 'Dockerfile-alt'
|
||||
}
|
||||
}
|
||||
},
|
||||
'tests/fixtures/extends',
|
||||
'filename.yml'
|
||||
)
|
||||
).services
|
||||
self.assertTrue('context' in service[0]['build'])
|
||||
self.assertEqual(service[0]['build']['dockerfile'], 'Dockerfile-alt')
|
||||
|
||||
service = config.load(
|
||||
build_config_details(
|
||||
{
|
||||
'version': 2,
|
||||
'services': {
|
||||
'web': {
|
||||
'build': {
|
||||
'context': '.',
|
||||
'dockerfile': 'Dockerfile-alt'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'tests/fixtures/extends',
|
||||
'filename.yml'
|
||||
)
|
||||
).services
|
||||
self.assertTrue('context' in service[0]['build'])
|
||||
self.assertEqual(service[0]['build']['dockerfile'], 'Dockerfile-alt')
|
||||
|
||||
def test_load_with_multiple_files_v2(self):
|
||||
base_file = config.ConfigFile(
|
||||
'base.yaml',
|
||||
|
|
@ -445,7 +499,7 @@ class ConfigTest(unittest.TestCase):
|
|||
expected = [
|
||||
{
|
||||
'name': 'web',
|
||||
'build': os.path.abspath('/'),
|
||||
'build': {'context': os.path.abspath('/')},
|
||||
'image': 'example/web',
|
||||
'volumes': [VolumeSpec.parse('/home/user/project:/code')],
|
||||
},
|
||||
|
|
@ -1157,7 +1211,7 @@ class BuildOrImageMergeTest(unittest.TestCase):
|
|||
|
||||
self.assertEqual(
|
||||
config.merge_service_dicts({'image': 'redis'}, {'build': '.'}, V1),
|
||||
{'build': '.'},
|
||||
{'build': '.'}
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1388,6 +1442,24 @@ class EnvTest(unittest.TestCase):
|
|||
},
|
||||
)
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_resolve_build_args(self):
|
||||
os.environ['env_arg'] = 'value2'
|
||||
|
||||
build = {
|
||||
'context': '.',
|
||||
'args': {
|
||||
'arg1': 'value1',
|
||||
'empty_arg': '',
|
||||
'env_arg': None,
|
||||
'no_env': None
|
||||
}
|
||||
}
|
||||
self.assertEqual(
|
||||
resolve_build_args(build),
|
||||
{'arg1': 'value1', 'empty_arg': '', 'env_arg': 'value2', 'no_env': ''},
|
||||
)
|
||||
|
||||
@pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason='paths use slash')
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_resolve_path(self):
|
||||
|
|
@ -1873,7 +1945,7 @@ class BuildPathTest(unittest.TestCase):
|
|||
|
||||
def test_from_file(self):
|
||||
service_dict = load_from_filename('tests/fixtures/build-path/docker-compose.yml')
|
||||
self.assertEquals(service_dict, [{'name': 'foo', 'build': self.abs_context_path}])
|
||||
self.assertEquals(service_dict, [{'name': 'foo', 'build': {'context': self.abs_context_path}}])
|
||||
|
||||
def test_valid_url_in_build_path(self):
|
||||
valid_urls = [
|
||||
|
|
@ -1888,7 +1960,7 @@ class BuildPathTest(unittest.TestCase):
|
|||
service_dict = config.load(build_config_details({
|
||||
'validurl': {'build': valid_url},
|
||||
}, '.', None)).services
|
||||
assert service_dict[0]['build'] == valid_url
|
||||
assert service_dict[0]['build'] == {'context': valid_url}
|
||||
|
||||
def test_invalid_url_in_build_path(self):
|
||||
invalid_urls = [
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ class ServiceTest(unittest.TestCase):
|
|||
self.assertEqual(parse_repository_tag("url:5000/repo@sha256:digest"), ("url:5000/repo", "sha256:digest", "@"))
|
||||
|
||||
def test_create_container_with_build(self):
|
||||
service = Service('foo', client=self.mock_client, build='.')
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
self.mock_client.inspect_image.side_effect = [
|
||||
NoSuchImageError,
|
||||
{'Id': 'abc123'},
|
||||
|
|
@ -374,17 +374,18 @@ class ServiceTest(unittest.TestCase):
|
|||
forcerm=False,
|
||||
nocache=False,
|
||||
rm=True,
|
||||
buildargs=None,
|
||||
)
|
||||
|
||||
def test_create_container_no_build(self):
|
||||
service = Service('foo', client=self.mock_client, build='.')
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
self.mock_client.inspect_image.return_value = {'Id': 'abc123'}
|
||||
|
||||
service.create_container(do_build=False)
|
||||
self.assertFalse(self.mock_client.build.called)
|
||||
|
||||
def test_create_container_no_build_but_needs_build(self):
|
||||
service = Service('foo', client=self.mock_client, build='.')
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
self.mock_client.inspect_image.side_effect = NoSuchImageError
|
||||
with self.assertRaises(NeedsBuildError):
|
||||
service.create_container(do_build=False)
|
||||
|
|
@ -394,7 +395,7 @@ class ServiceTest(unittest.TestCase):
|
|||
b'{"stream": "Successfully built 12345"}',
|
||||
]
|
||||
|
||||
service = Service('foo', client=self.mock_client, build='.')
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
service.build()
|
||||
|
||||
self.assertEqual(self.mock_client.build.call_count, 1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue