diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 13fb9bac0..85ab9015f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,4 +3,4 @@ # # KEEP THIS FILE SORTED. Order is important. Last match takes precedence. -* @ndeloof @rumpl @ulyssessouza +* @aiordache @ndeloof @rumpl @ulyssessouza diff --git a/MAINTAINERS b/MAINTAINERS index 273f724ec..7e178147e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11,6 +11,7 @@ [Org] [Org."Core maintainers"] people = [ + "aiordache", "ndeloof", "rumpl", "ulyssessouza", @@ -53,6 +54,11 @@ Email = "aanand.prasad@gmail.com" GitHub = "aanand" + [people.aiordache] + Name = "Anca Iordache" + Email = "anca.iordache@docker.com" + GitHub = "aiordache" + [people.bfirsh] Name = "Ben Firshman" Email = "ben@firshman.co.uk" diff --git a/compose/cli/main.py b/compose/cli/main.py index b07b2b728..acac12246 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -73,13 +73,16 @@ def main(): log.error(e.msg) sys.exit(1) except BuildError as e: - log.error("Service '{}' failed to build: {}".format(e.service.name, e.reason)) + reason = "" + if e.reason: + reason = " : " + e.reason + log.error("Service '{}' failed to build{}".format(e.service.name, reason)) sys.exit(1) except StreamOutputError as e: log.error(e) sys.exit(1) except NeedsBuildError as e: - log.error("Service '%s' needs to be built, but --no-build was passed." % e.service.name) + log.error("Service '{}' needs to be built, but --no-build was passed.".format(e.service.name)) sys.exit(1) except NoSuchCommand as e: commands = "\n".join(parse_doc_section("commands:", getdoc(e.supercommand))) @@ -1436,6 +1439,7 @@ def call_docker(args, dockeropts, environment): key = dockeropts.get('--tlskey') verify = dockeropts.get('--tlsverify') host = dockeropts.get('--host') + context = dockeropts.get('--context') tls_options = [] if tls: tls_options.append('--tls') @@ -1451,6 +1455,10 @@ def call_docker(args, dockeropts, environment): tls_options.extend( ['--host', re.sub(r'^https?://', 'tcp://', host.lstrip('='))] ) + if context: + tls_options.extend( + ['--context', context] + ) args = [executable_path] + tls_options + args log.debug(" ".join(map(pipes.quote, args))) diff --git a/compose/service.py b/compose/service.py index 471f9e199..70939cac7 100644 --- a/compose/service.py +++ b/compose/service.py @@ -1856,7 +1856,8 @@ class _CLIBuilder: magic_word = "Successfully built " appear = False - with subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) as p: + with subprocess.Popen(args, stdout=subprocess.PIPE, + universal_newlines=True) as p: while True: line = p.stdout.readline() if not line: @@ -1865,6 +1866,10 @@ class _CLIBuilder: appear = True yield json.dumps({"stream": line}) + p.communicate() + if p.returncode != 0: + raise StreamOutputError() + with open(iidfile) as f: line = f.readline() image_id = line.split(":")[1].strip() diff --git a/requirements-dev.txt b/requirements-dev.txt index 1695e98e2..8655e5c0a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,4 +6,4 @@ gitpython==3.1.7 mock==3.0.5 pytest==6.0.1; python_version >= '3.5' pytest==4.6.5; python_version < '3.5' -pytest-cov==2.10.0 +pytest-cov==2.10.1 diff --git a/requirements-indirect.txt b/requirements-indirect.txt index ef302dcdf..9d9ae3684 100644 --- a/requirements-indirect.txt +++ b/requirements-indirect.txt @@ -1,6 +1,6 @@ altgraph==0.17 appdirs==1.4.4 -attrs==19.3.0 +attrs==20.1.0 bcrypt==3.1.7 cffi==1.14.1 cryptography==3.0 diff --git a/setup.py b/setup.py index 590e0ebdc..e0d4340e5 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ install_requires = [ 'texttable >= 0.9.0, < 2', 'websocket-client >= 0.32.0, < 1', 'distro >= 1.5.0, < 2', - 'docker[ssh] >= 4.2.2, < 5', + 'docker[ssh] >= 4.3.1, < 5', 'dockerpty >= 0.4.1, < 1', 'jsonschema >= 2.5.1, < 4', 'python-dotenv >= 0.13.0, < 1', diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index 985c4d77a..efb1fd5fa 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -36,6 +36,7 @@ from compose.parallel import ParallelStreamWriter from compose.project import OneOffFilter from compose.project import Project from compose.service import BuildAction +from compose.service import BuildError from compose.service import ConvergencePlan from compose.service import ConvergenceStrategy from compose.service import IpcMode @@ -987,6 +988,23 @@ class ServiceTest(DockerClientTestCase): image = self.client.inspect_image('composetest_web') assert image['Config']['Labels']['com.docker.compose.test'] + def test_build_cli_with_build_error(self): + base_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, base_dir) + + with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f: + f.write('\n'.join([ + "FROM busybox", + "RUN exit 2", + ])) + service = self.create_service('web', + build={ + 'context': base_dir, + 'labels': {'com.docker.compose.test': 'true'}}, + ) + with pytest.raises(BuildError): + service.build(cli=True) + def test_up_build_cli(self): base_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, base_dir)