mirror of
https://github.com/docker/compose.git
synced 2026-02-15 21:19:30 +08:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc93c97689 | ||
|
|
a82fef0722 | ||
|
|
f70b8c9a53 | ||
|
|
b572a1e2e0 | ||
|
|
37eb7a509b | ||
|
|
cba8ad474c | ||
|
|
e9220f45df | ||
|
|
780a425c60 | ||
|
|
d32b9f95ca | ||
|
|
a23f39127e | ||
|
|
d92e9beec1 | ||
|
|
8ebd7f96f0 | ||
|
|
b7a675b1c0 | ||
|
|
8820343882 | ||
|
|
fedc8f71ad | ||
|
|
e82d38f333 | ||
|
|
d6b5d324e2 | ||
|
|
44edd65065 | ||
|
|
55c5c8e8ac | ||
|
|
517efbf386 | ||
|
|
c8cfc590cc | ||
|
|
a7e8356651 | ||
|
|
332fa8bf62 | ||
|
|
a83d86e7ce | ||
|
|
1de8205996 | ||
|
|
d837d27ad7 | ||
|
|
cfc131b502 | ||
|
|
e6ec77047b | ||
|
|
f4cf7a939e | ||
|
|
fa9e8bd641 | ||
|
|
e13a7213f1 | ||
|
|
fe2b692547 | ||
|
|
962421d019 | ||
|
|
4038169d96 | ||
|
|
b42d4197ce | ||
|
|
0a186604be | ||
|
|
d072601197 | ||
|
|
a0592ce585 | ||
|
|
c49678a11f | ||
|
|
aeddfd41d6 | ||
|
|
b9a4581d60 | ||
|
|
f6b6cd22df | ||
|
|
8f3c9c58c5 | ||
|
|
52c3e94be0 | ||
|
|
ea22d5821c | ||
|
|
c7e82489f4 | ||
|
|
952340043a | ||
|
|
2c668e237d | ||
|
|
661ac20e5d | ||
|
|
ab93b87f04 | ||
|
|
85d940909e | ||
|
|
4667896b69 | ||
|
|
a78e3b0c7c | ||
|
|
5e7521909d | ||
|
|
272e85dce3 | ||
|
|
2bc4161526 | ||
|
|
8552e8e283 | ||
|
|
3803d35c03 | ||
|
|
d9fa8158c3 | ||
|
|
0aa590649c | ||
|
|
eb2fdf81b4 | ||
|
|
917c2701f2 | ||
|
|
3a3288c54b | ||
|
|
428942498b | ||
|
|
c54341758a | ||
|
|
662761dbba | ||
|
|
0e05ac6d2c | ||
|
|
295dd9abda | ||
|
|
81b30c4380 | ||
|
|
360753ecc1 | ||
|
|
3fae0119ca | ||
|
|
0fdb9783cd | ||
|
|
0dec6b5ff1 | ||
|
|
e0412a2488 | ||
|
|
3fc5c6f563 | ||
|
|
28310b3ba4 | ||
|
|
4585db124a | ||
|
|
1f9b20d97b | ||
|
|
82a89aef1c | ||
|
|
3934617e37 | ||
|
|
82db4fd4f2 | ||
|
|
0f3d4ddaa7 | ||
|
|
2007951731 | ||
|
|
60f8ce09f9 |
@@ -32,6 +32,9 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: dist/docker-compose-Darwin-x86_64
|
||||
destination: docker-compose-Darwin-x86_64
|
||||
- store_artifacts:
|
||||
path: dist/docker-compose-Darwin-x86_64.tgz
|
||||
destination: docker-compose-Darwin-x86_64.tgz
|
||||
- deploy:
|
||||
name: Deploy binary to bintray
|
||||
command: |
|
||||
|
||||
6
.github/CODEOWNERS
vendored
Normal file
6
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# GitHub code owners
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
#
|
||||
# KEEP THIS FILE SORTED. Order is important. Last match takes precedence.
|
||||
|
||||
* @ndeloof @rumpl @ulyssessouza
|
||||
130
CHANGELOG.md
130
CHANGELOG.md
@@ -1,6 +1,136 @@
|
||||
Change log
|
||||
==========
|
||||
|
||||
1.25.1 (2020-01-06)
|
||||
-------------------
|
||||
|
||||
### Features
|
||||
|
||||
- Bump `pytest-cov` 2.8.1
|
||||
|
||||
- Bump `flake8` 3.7.9
|
||||
|
||||
- Bump `coverage` 4.5.4
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Decode APIError explanation to unicode before usage on start and create of a container
|
||||
|
||||
- Reports when images that cannot be pulled and must be built
|
||||
|
||||
- Discard label `com.docker.compose.filepaths` having None as value. Typically, when coming from stdin
|
||||
|
||||
- Added OSX binary as a directory to solve slow start up time caused by MacOS Catalina binary scan
|
||||
|
||||
- Passed in HOME env-var in container mode (running with `script/run/run.sh`)
|
||||
|
||||
- Reverted behavior of "only pull images that we can't build" and replace by a warning informing the image we can't pull and must be built
|
||||
|
||||
|
||||
1.25.0 (2019-11-18)
|
||||
-------------------
|
||||
|
||||
### Features
|
||||
|
||||
- Set no-colors to true if CLICOLOR env variable is set to 0
|
||||
|
||||
- Add working dir, config files and env file in service labels
|
||||
|
||||
- Add dependencies for ARM build
|
||||
|
||||
- Add BuildKit support, use `DOCKER_BUILDKIT=1` and `COMPOSE_DOCKER_CLI_BUILD=1`
|
||||
|
||||
- Bump paramiko to 2.6.0
|
||||
|
||||
- Add working dir, config files and env file in service labels
|
||||
|
||||
- Add tag `docker-compose:latest`
|
||||
|
||||
- Add `docker-compose:<version>-alpine` image/tag
|
||||
|
||||
- Add `docker-compose:<version>-debian` image/tag
|
||||
|
||||
- Bumped `docker-py` 4.1.0
|
||||
|
||||
- Supports `requests` up to 2.22.0 version
|
||||
|
||||
- Drops empty tag on `build:cache_from`
|
||||
|
||||
- `Dockerfile` now generates `libmusl` binaries for alpine
|
||||
|
||||
- Only pull images that can't be built
|
||||
|
||||
- Attribute `scale` can now accept `0` as a value
|
||||
|
||||
- Added `--quiet` build flag
|
||||
|
||||
- Added `--no-interpolate` to `docker-compose config`
|
||||
|
||||
- Bump OpenSSL for macOS build (`1.1.0j` to `1.1.1c`)
|
||||
|
||||
- Added `--no-rm` to `build` command
|
||||
|
||||
- Added support for `credential_spec`
|
||||
|
||||
- Resolve digests without pulling image
|
||||
|
||||
- Upgrade `pyyaml` to `4.2b1`
|
||||
|
||||
- Lowered severity to `warning` if `down` tries to remove nonexisting image
|
||||
|
||||
- Use improved API fields for project events when possible
|
||||
|
||||
- Update `setup.py` for modern `pypi/setuptools` and remove `pandoc` dependencies
|
||||
|
||||
- Removed `Dockerfile.armhf` which is no longer needed
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Make container service color deterministic, remove red from chosen colors
|
||||
|
||||
- Fix non ascii chars error. Python2 only
|
||||
|
||||
- Format image size as decimal to be align with Docker CLI
|
||||
|
||||
- Use Python Posix support to get tty size
|
||||
|
||||
- Fix same file 'extends' optimization
|
||||
|
||||
- Use python POSIX support to get tty size
|
||||
|
||||
- Format image size as decimal to be align with Docker CLI
|
||||
|
||||
- Fixed stdin_open
|
||||
|
||||
- Fixed `--remove-orphans` when used with `up --no-start`
|
||||
|
||||
- Fixed `docker-compose ps --all`
|
||||
|
||||
- Fixed `depends_on` dependency recreation behavior
|
||||
|
||||
- Fixed bash completion for `build --memory`
|
||||
|
||||
- Fixed misleading warning concerning env vars when performing an `exec` command
|
||||
|
||||
- Fixed failure check in parallel_execute_watch
|
||||
|
||||
- Fixed race condition after pulling image
|
||||
|
||||
- Fixed error on duplicate mount points
|
||||
|
||||
- Fixed merge on networks section
|
||||
|
||||
- Always connect Compose container to `stdin`
|
||||
|
||||
- Fixed the presentation of failed services on 'docker-compose start' when containers are not available
|
||||
|
||||
1.24.1 (2019-06-24)
|
||||
-------------------
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Fixed acceptance tests
|
||||
|
||||
1.24.0 (2019-03-28)
|
||||
-------------------
|
||||
|
||||
|
||||
9
Jenkinsfile
vendored
9
Jenkinsfile
vendored
@@ -31,7 +31,7 @@ def get_versions = { String imageId, int number ->
|
||||
def docker_versions
|
||||
wrappedNode(label: "ubuntu && amd64 && !zfs") {
|
||||
def result = sh(script: """docker run --rm \\
|
||||
--entrypoint=/code/.tox/py37/bin/python \\
|
||||
--entrypoint=/code/.tox/py27/bin/python \\
|
||||
${imageId} \\
|
||||
/code/script/test/versions.py -n ${number} docker/docker-ce recent
|
||||
""", returnStdout: true
|
||||
@@ -48,7 +48,7 @@ def runTests = { Map settings ->
|
||||
def imageName = settings.get("image", null)
|
||||
|
||||
if (!pythonVersions) {
|
||||
throw new Exception("Need Python versions to test. e.g.: `runTests(pythonVersions: 'py37')`")
|
||||
throw new Exception("Need Python versions to test. e.g.: `runTests(pythonVersions: 'py27,py37')`")
|
||||
}
|
||||
if (!dockerVersions) {
|
||||
throw new Exception("Need Docker versions to test. e.g.: `runTests(dockerVersions: 'all')`")
|
||||
@@ -82,10 +82,13 @@ def runTests = { Map settings ->
|
||||
|
||||
def testMatrix = [failFast: true]
|
||||
def baseImages = ['alpine', 'debian']
|
||||
def pythonVersions = ['py27', 'py37']
|
||||
baseImages.each { baseImage ->
|
||||
def imageName = buildImage(baseImage)
|
||||
get_versions(imageName, 2).each { dockerVersion ->
|
||||
testMatrix["${baseImage}_${dockerVersion}"] = runTests([baseImage: baseImage, image: imageName, dockerVersions: dockerVersion, pythonVersions: 'py37'])
|
||||
pythonVersions.each { pyVersion ->
|
||||
testMatrix["${baseImage}_${dockerVersion}_${pyVersion}"] = runTests([baseImage: baseImage, image: imageName, dockerVersions: dockerVersion, pythonVersions: pyVersion])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[Org]
|
||||
[Org."Core maintainers"]
|
||||
people = [
|
||||
"ndeloof",
|
||||
"rumpl",
|
||||
"ulyssessouza",
|
||||
]
|
||||
@@ -77,6 +78,11 @@
|
||||
Email = "mazz@houseofmnowster.com"
|
||||
GitHub = "mnowster"
|
||||
|
||||
[people.ndeloof]
|
||||
Name = "Nicolas De Loof"
|
||||
Email = "nicolas.deloof@gmail.com"
|
||||
GitHub = "ndeloof"
|
||||
|
||||
[people.rumpl]
|
||||
Name = "Djordje Lukic"
|
||||
Email = "djordje.lukic@docker.com"
|
||||
|
||||
@@ -2,6 +2,8 @@ Docker Compose
|
||||
==============
|
||||

|
||||
|
||||
## :exclamation: The docker-compose project announces that as Python 2 reaches it's EOL, versions 1.25.x will be the last to support it. For more information, please refer to this [issue](https://github.com/docker/compose/issues/6890).
|
||||
|
||||
Compose is a tool for defining and running multi-container Docker applications.
|
||||
With Compose, you use a Compose file to configure your application's services.
|
||||
Then, using a single command, you create and start all the services
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__version__ = '1.25.0dev'
|
||||
__version__ = '1.25.1'
|
||||
|
||||
@@ -159,15 +159,25 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False,
|
||||
|
||||
def execution_context_labels(config_details, environment_file):
|
||||
extra_labels = [
|
||||
'{0}={1}'.format(LABEL_WORKING_DIR, os.path.abspath(config_details.working_dir)),
|
||||
'{0}={1}'.format(LABEL_CONFIG_FILES, config_files_label(config_details)),
|
||||
'{0}={1}'.format(LABEL_WORKING_DIR, os.path.abspath(config_details.working_dir))
|
||||
]
|
||||
|
||||
if not use_config_from_stdin(config_details):
|
||||
extra_labels.append('{0}={1}'.format(LABEL_CONFIG_FILES, config_files_label(config_details)))
|
||||
|
||||
if environment_file is not None:
|
||||
extra_labels.append('{0}={1}'.format(LABEL_ENVIRONMENT_FILE,
|
||||
os.path.normpath(environment_file)))
|
||||
return extra_labels
|
||||
|
||||
|
||||
def use_config_from_stdin(config_details):
|
||||
for c in config_details.config_files:
|
||||
if not c.filename:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def config_files_label(config_details):
|
||||
return ",".join(
|
||||
map(str, (os.path.normpath(c.filename) for c in config_details.config_files)))
|
||||
|
||||
@@ -114,3 +114,13 @@ def get_digest_from_push(events):
|
||||
if digest:
|
||||
return digest
|
||||
return None
|
||||
|
||||
|
||||
def read_status(event):
|
||||
status = event['status'].lower()
|
||||
if 'progressDetail' in event:
|
||||
detail = event['progressDetail']
|
||||
if 'current' in detail and 'total' in detail:
|
||||
percentage = float(detail['current']) / float(detail['total'])
|
||||
status = '{} ({:.1%})'.format(status, percentage)
|
||||
return status
|
||||
|
||||
@@ -11,6 +11,8 @@ from os import path
|
||||
import enum
|
||||
import six
|
||||
from docker.errors import APIError
|
||||
from docker.errors import ImageNotFound
|
||||
from docker.errors import NotFound
|
||||
from docker.utils import version_lt
|
||||
|
||||
from . import parallel
|
||||
@@ -25,6 +27,7 @@ from .container import Container
|
||||
from .network import build_networks
|
||||
from .network import get_networks
|
||||
from .network import ProjectNetworks
|
||||
from .progress_stream import read_status
|
||||
from .service import BuildAction
|
||||
from .service import ContainerNetworkMode
|
||||
from .service import ContainerPidMode
|
||||
@@ -619,49 +622,68 @@ class Project(object):
|
||||
def pull(self, service_names=None, ignore_pull_failures=False, parallel_pull=False, silent=False,
|
||||
include_deps=False):
|
||||
services = self.get_services(service_names, include_deps)
|
||||
images_to_build = {service.image_name for service in services if service.can_be_built()}
|
||||
services_to_pull = [service for service in services if service.image_name not in images_to_build]
|
||||
|
||||
msg = not silent and 'Pulling' or None
|
||||
|
||||
if parallel_pull:
|
||||
def pull_service(service):
|
||||
strm = service.pull(ignore_pull_failures, True, stream=True)
|
||||
if strm is None: # Attempting to pull service with no `image` key is a no-op
|
||||
return
|
||||
self.parallel_pull(services, silent=silent)
|
||||
|
||||
else:
|
||||
must_build = []
|
||||
for service in services:
|
||||
try:
|
||||
service.pull(ignore_pull_failures, silent=silent)
|
||||
except (ImageNotFound, NotFound):
|
||||
if service.can_be_built():
|
||||
must_build.append(service.name)
|
||||
else:
|
||||
raise
|
||||
|
||||
if len(must_build):
|
||||
log.warning('Some service image(s) must be built from source by running:\n'
|
||||
' docker-compose build {}'
|
||||
.format(' '.join(must_build)))
|
||||
|
||||
def parallel_pull(self, services, ignore_pull_failures=False, silent=False):
|
||||
msg = 'Pulling' if not silent else None
|
||||
must_build = []
|
||||
|
||||
def pull_service(service):
|
||||
strm = service.pull(ignore_pull_failures, True, stream=True)
|
||||
|
||||
if strm is None: # Attempting to pull service with no `image` key is a no-op
|
||||
return
|
||||
|
||||
try:
|
||||
writer = parallel.get_stream_writer()
|
||||
|
||||
for event in strm:
|
||||
if 'status' not in event:
|
||||
continue
|
||||
status = event['status'].lower()
|
||||
if 'progressDetail' in event:
|
||||
detail = event['progressDetail']
|
||||
if 'current' in detail and 'total' in detail:
|
||||
percentage = float(detail['current']) / float(detail['total'])
|
||||
status = '{} ({:.1%})'.format(status, percentage)
|
||||
|
||||
status = read_status(event)
|
||||
writer.write(
|
||||
msg, service.name, truncate_string(status), lambda s: s
|
||||
)
|
||||
except (ImageNotFound, NotFound):
|
||||
if service.can_be_built():
|
||||
must_build.append(service.name)
|
||||
else:
|
||||
raise
|
||||
|
||||
_, errors = parallel.parallel_execute(
|
||||
services_to_pull,
|
||||
pull_service,
|
||||
operator.attrgetter('name'),
|
||||
msg,
|
||||
limit=5,
|
||||
)
|
||||
if len(errors):
|
||||
combined_errors = '\n'.join([
|
||||
e.decode('utf-8') if isinstance(e, six.binary_type) else e for e in errors.values()
|
||||
])
|
||||
raise ProjectError(combined_errors)
|
||||
_, errors = parallel.parallel_execute(
|
||||
services,
|
||||
pull_service,
|
||||
operator.attrgetter('name'),
|
||||
msg,
|
||||
limit=5,
|
||||
)
|
||||
|
||||
else:
|
||||
for service in services_to_pull:
|
||||
service.pull(ignore_pull_failures, silent=silent)
|
||||
if len(must_build):
|
||||
log.warning('Some service image(s) must be built from source by running:\n'
|
||||
' docker-compose build {}'
|
||||
.format(' '.join(must_build)))
|
||||
if len(errors):
|
||||
combined_errors = '\n'.join([
|
||||
e.decode('utf-8') if isinstance(e, six.binary_type) else e for e in errors.values()
|
||||
])
|
||||
raise ProjectError(combined_errors)
|
||||
|
||||
def push(self, service_names=None, ignore_push_failures=False):
|
||||
unique_images = set()
|
||||
|
||||
@@ -60,6 +60,7 @@ from .utils import parse_bytes
|
||||
from .utils import parse_seconds_float
|
||||
from .utils import truncate_id
|
||||
from .utils import unique_everseen
|
||||
from compose.cli.utils import binarystr_to_unicode
|
||||
|
||||
if six.PY2:
|
||||
import subprocess32 as subprocess
|
||||
@@ -343,7 +344,7 @@ class Service(object):
|
||||
return Container.create(self.client, **container_options)
|
||||
except APIError as ex:
|
||||
raise OperationFailedError("Cannot create container for service %s: %s" %
|
||||
(self.name, ex.explanation))
|
||||
(self.name, binarystr_to_unicode(ex.explanation)))
|
||||
|
||||
def ensure_image_exists(self, do_build=BuildAction.none, silent=False, cli=False):
|
||||
if self.can_be_built() and do_build == BuildAction.force:
|
||||
@@ -624,9 +625,10 @@ class Service(object):
|
||||
try:
|
||||
container.start()
|
||||
except APIError as ex:
|
||||
if "driver failed programming external connectivity" in ex.explanation:
|
||||
expl = binarystr_to_unicode(ex.explanation)
|
||||
if "driver failed programming external connectivity" in expl:
|
||||
log.warn("Host is already in use by another container")
|
||||
raise OperationFailedError("Cannot start service %s: %s" % (self.name, ex.explanation))
|
||||
raise OperationFailedError("Cannot start service %s: %s" % (self.name, expl))
|
||||
return container
|
||||
|
||||
@property
|
||||
|
||||
108
docker-compose_darwin.spec
Normal file
108
docker-compose_darwin.spec
Normal file
@@ -0,0 +1,108 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(['bin/docker-compose'],
|
||||
pathex=['.'],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
cipher=block_cipher)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
name='docker-compose',
|
||||
debug=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=True,
|
||||
bootloader_ignore_signals=True)
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[
|
||||
(
|
||||
'compose/config/config_schema_v1.json',
|
||||
'compose/config/config_schema_v1.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v2.0.json',
|
||||
'compose/config/config_schema_v2.0.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v2.1.json',
|
||||
'compose/config/config_schema_v2.1.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v2.2.json',
|
||||
'compose/config/config_schema_v2.2.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v2.3.json',
|
||||
'compose/config/config_schema_v2.3.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v2.4.json',
|
||||
'compose/config/config_schema_v2.4.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.0.json',
|
||||
'compose/config/config_schema_v3.0.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.1.json',
|
||||
'compose/config/config_schema_v3.1.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.2.json',
|
||||
'compose/config/config_schema_v3.2.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.3.json',
|
||||
'compose/config/config_schema_v3.3.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.4.json',
|
||||
'compose/config/config_schema_v3.4.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.5.json',
|
||||
'compose/config/config_schema_v3.5.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.6.json',
|
||||
'compose/config/config_schema_v3.6.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/config/config_schema_v3.7.json',
|
||||
'compose/config/config_schema_v3.7.json',
|
||||
'DATA'
|
||||
),
|
||||
(
|
||||
'compose/GITSHA',
|
||||
'compose/GITSHA',
|
||||
'DATA'
|
||||
)
|
||||
],
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='docker-compose-Darwin-x86_64')
|
||||
@@ -1,6 +1,6 @@
|
||||
coverage==4.4.2
|
||||
coverage==4.5.4
|
||||
ddt==1.2.0
|
||||
flake8==3.5.0
|
||||
flake8==3.7.9
|
||||
mock==3.0.5
|
||||
pytest==3.6.3
|
||||
pytest-cov==2.5.1
|
||||
pytest-cov==2.8.1
|
||||
|
||||
@@ -11,6 +11,14 @@ venv/bin/pip install -r requirements-build.txt
|
||||
venv/bin/pip install --no-deps .
|
||||
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
|
||||
echo "${DOCKER_COMPOSE_GITSHA}" > compose/GITSHA
|
||||
|
||||
# Build as a folder for macOS Catalina.
|
||||
venv/bin/pyinstaller docker-compose_darwin.spec
|
||||
dist/docker-compose-Darwin-x86_64/docker-compose version
|
||||
(cd dist/docker-compose-Darwin-x86_64/ && tar zcvf ../docker-compose-Darwin-x86_64.tgz .)
|
||||
rm -rf dist/docker-compose-Darwin-x86_64
|
||||
|
||||
# Build static binary for legacy.
|
||||
venv/bin/pyinstaller docker-compose.spec
|
||||
mv dist/docker-compose dist/docker-compose-Darwin-x86_64
|
||||
dist/docker-compose-Darwin-x86_64 version
|
||||
|
||||
@@ -25,3 +25,11 @@ curl -f -T dist/docker-compose-${OS_NAME}-x86_64 -u$BINTRAY_USERNAME:$BINTRAY_AP
|
||||
-H "X-Bintray-Package: ${PKG_NAME}" -H "X-Bintray-Version: $CIRCLE_BRANCH" \
|
||||
-H "X-Bintray-Override: 1" -H "X-Bintray-Publish: 1" -X PUT \
|
||||
https://api.bintray.com/content/docker-compose/${CIRCLE_BRANCH}/docker-compose-${OS_NAME}-x86_64 || exit 1
|
||||
|
||||
# Upload folder format of docker-compose for macOS in addition to binary.
|
||||
if [ "${OS_NAME}" == "Darwin" ]; then
|
||||
curl -f -T dist/docker-compose-${OS_NAME}-x86_64.tgz -u$BINTRAY_USERNAME:$BINTRAY_API_KEY \
|
||||
-H "X-Bintray-Package: ${PKG_NAME}" -H "X-Bintray-Version: $CIRCLE_BRANCH" \
|
||||
-H "X-Bintray-Override: 1" -H "X-Bintray-Publish: 1" -X PUT \
|
||||
https://api.bintray.com/content/docker-compose/${CIRCLE_BRANCH}/docker-compose-${OS_NAME}-x86_64.tgz || exit 1
|
||||
fi
|
||||
|
||||
@@ -204,7 +204,8 @@ def resume(args):
|
||||
gh_release = create_release_draft(repository, args.release, pr_data, files)
|
||||
delete_assets(gh_release)
|
||||
upload_assets(gh_release, files)
|
||||
img_manager = ImageManager(args.release)
|
||||
tag_as_latest = is_tag_latest(args.release)
|
||||
img_manager = ImageManager(args.release, tag_as_latest)
|
||||
img_manager.build_images(repository)
|
||||
except ScriptError as e:
|
||||
print(e)
|
||||
@@ -244,7 +245,8 @@ def start(args):
|
||||
files = downloader.download_all(args.release)
|
||||
gh_release = create_release_draft(repository, args.release, pr_data, files)
|
||||
upload_assets(gh_release, files)
|
||||
img_manager = ImageManager(args.release)
|
||||
tag_as_latest = is_tag_latest(args.release)
|
||||
img_manager = ImageManager(args.release, tag_as_latest)
|
||||
img_manager.build_images(repository)
|
||||
except ScriptError as e:
|
||||
print(e)
|
||||
|
||||
@@ -55,6 +55,7 @@ class BinaryDownloader(requests.Session):
|
||||
|
||||
def download_all(self, version):
|
||||
files = {
|
||||
'docker-compose-Darwin-x86_64.tgz': None,
|
||||
'docker-compose-Darwin-x86_64': None,
|
||||
'docker-compose-Linux-x86_64': None,
|
||||
'docker-compose-Windows-x86_64.exe': None,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
VERSION="1.24.0"
|
||||
VERSION="1.25.1"
|
||||
IMAGE="docker/compose:$VERSION"
|
||||
|
||||
|
||||
@@ -36,18 +36,18 @@ if [ "$(pwd)" != '/' ]; then
|
||||
fi
|
||||
if [ -n "$COMPOSE_FILE" ]; then
|
||||
COMPOSE_OPTIONS="$COMPOSE_OPTIONS -e COMPOSE_FILE=$COMPOSE_FILE"
|
||||
compose_dir=$(realpath $(dirname $COMPOSE_FILE))
|
||||
compose_dir=$(realpath "$(dirname "$COMPOSE_FILE")")
|
||||
fi
|
||||
# TODO: also check --file argument
|
||||
if [ -n "$compose_dir" ]; then
|
||||
VOLUMES="$VOLUMES -v $compose_dir:$compose_dir"
|
||||
fi
|
||||
if [ -n "$HOME" ]; then
|
||||
VOLUMES="$VOLUMES -v $HOME:$HOME -v $HOME:/root" # mount $HOME in /root to share docker.config
|
||||
VOLUMES="$VOLUMES -v $HOME:$HOME -e HOME" # Pass in HOME to share docker.config and allow ~/-relative paths to work.
|
||||
fi
|
||||
|
||||
# Only allocate tty if we detect one
|
||||
if [ -t 0 -a -t 1 ]; then
|
||||
if [ -t 0 ] && [ -t 1 ]; then
|
||||
DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -t"
|
||||
fi
|
||||
|
||||
@@ -56,8 +56,9 @@ DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -i"
|
||||
|
||||
|
||||
# Handle userns security
|
||||
if [ ! -z "$(docker info 2>/dev/null | grep userns)" ]; then
|
||||
if docker info --format '{{json .SecurityOptions}}' 2>/dev/null | grep -q 'name=userns'; then
|
||||
DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS --userns=host"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" $IMAGE "$@"
|
||||
|
||||
@@ -36,7 +36,7 @@ if ! [ -x "$(command -v python3)" ]; then
|
||||
brew install python3
|
||||
fi
|
||||
if ! [ -x "$(command -v virtualenv)" ]; then
|
||||
pip install virtualenv==16.2.0
|
||||
pip3 install virtualenv==16.2.0
|
||||
fi
|
||||
|
||||
#
|
||||
|
||||
@@ -48,6 +48,7 @@ BUILD_PULL_TEXT = 'Status: Image is up to date for busybox:1.27.2'
|
||||
def start_process(base_dir, options):
|
||||
proc = subprocess.Popen(
|
||||
['docker-compose'] + options,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
cwd=base_dir)
|
||||
@@ -55,8 +56,8 @@ def start_process(base_dir, options):
|
||||
return proc
|
||||
|
||||
|
||||
def wait_on_process(proc, returncode=0):
|
||||
stdout, stderr = proc.communicate()
|
||||
def wait_on_process(proc, returncode=0, stdin=None):
|
||||
stdout, stderr = proc.communicate(input=stdin)
|
||||
if proc.returncode != returncode:
|
||||
print("Stderr: {}".format(stderr))
|
||||
print("Stdout: {}".format(stdout))
|
||||
@@ -64,10 +65,10 @@ def wait_on_process(proc, returncode=0):
|
||||
return ProcessResult(stdout.decode('utf-8'), stderr.decode('utf-8'))
|
||||
|
||||
|
||||
def dispatch(base_dir, options, project_options=None, returncode=0):
|
||||
def dispatch(base_dir, options, project_options=None, returncode=0, stdin=None):
|
||||
project_options = project_options or []
|
||||
proc = start_process(base_dir, project_options + options)
|
||||
return wait_on_process(proc, returncode=returncode)
|
||||
return wait_on_process(proc, returncode=returncode, stdin=stdin)
|
||||
|
||||
|
||||
def wait_on_condition(condition, delay=0.1, timeout=40):
|
||||
@@ -156,8 +157,8 @@ class CLITestCase(DockerClientTestCase):
|
||||
self._project = get_project(self.base_dir, override_dir=self.override_dir)
|
||||
return self._project
|
||||
|
||||
def dispatch(self, options, project_options=None, returncode=0):
|
||||
return dispatch(self.base_dir, options, project_options, returncode)
|
||||
def dispatch(self, options, project_options=None, returncode=0, stdin=None):
|
||||
return dispatch(self.base_dir, options, project_options, returncode, stdin)
|
||||
|
||||
def execute(self, container, cmd):
|
||||
# Remove once Hijack and CloseNotifier sign a peace treaty
|
||||
@@ -241,6 +242,17 @@ class CLITestCase(DockerClientTestCase):
|
||||
self.base_dir = 'tests/fixtures/v2-full'
|
||||
assert self.dispatch(['config', '--quiet']).stdout == ''
|
||||
|
||||
def test_config_stdin(self):
|
||||
config = b"""version: "3.7"
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
other:
|
||||
image: alpine
|
||||
"""
|
||||
result = self.dispatch(['-f', '-', 'config', '--services'], stdin=config)
|
||||
assert set(result.stdout.rstrip().split('\n')) == {'web', 'other'}
|
||||
|
||||
def test_config_with_hash_option(self):
|
||||
self.base_dir = 'tests/fixtures/v2-full'
|
||||
result = self.dispatch(['config', '--hash=*'])
|
||||
@@ -661,13 +673,6 @@ class CLITestCase(DockerClientTestCase):
|
||||
'image library/nonexisting-image:latest not found' in result.stderr or
|
||||
'pull access denied for nonexisting-image' in result.stderr)
|
||||
|
||||
def test_pull_with_build(self):
|
||||
result = self.dispatch(['-f', 'pull-with-build.yml', 'pull'])
|
||||
|
||||
assert 'Pulling simple' not in result.stderr
|
||||
assert 'Pulling from_simple' not in result.stderr
|
||||
assert 'Pulling another ...' in result.stderr
|
||||
|
||||
def test_pull_with_quiet(self):
|
||||
assert self.dispatch(['pull', '--quiet']).stderr == ''
|
||||
assert self.dispatch(['pull', '--quiet']).stdout == ''
|
||||
@@ -689,6 +694,14 @@ class CLITestCase(DockerClientTestCase):
|
||||
result.stderr
|
||||
)
|
||||
|
||||
def test_pull_can_build(self):
|
||||
result = self.dispatch([
|
||||
'-f', 'can-build-pull-failures.yml', 'pull'],
|
||||
returncode=0
|
||||
)
|
||||
assert 'Some service image(s) must be built from source' in result.stderr
|
||||
assert 'docker-compose build can_build' in result.stderr
|
||||
|
||||
def test_pull_with_no_deps(self):
|
||||
self.base_dir = 'tests/fixtures/links-composefile'
|
||||
result = self.dispatch(['pull', '--no-parallel', 'web'])
|
||||
|
||||
6
tests/fixtures/simple-composefile/can-build-pull-failures.yml
vendored
Normal file
6
tests/fixtures/simple-composefile/can-build-pull-failures.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: '3'
|
||||
services:
|
||||
can_build:
|
||||
image: nonexisting-image-but-can-build:latest
|
||||
build: .
|
||||
command: top
|
||||
@@ -521,7 +521,37 @@ class ServiceTest(unittest.TestCase):
|
||||
assert 'was built because it did not already exist' in args[0]
|
||||
|
||||
assert self.mock_client.build.call_count == 1
|
||||
self.mock_client.build.call_args[1]['tag'] == 'default_foo'
|
||||
assert self.mock_client.build.call_args[1]['tag'] == 'default_foo'
|
||||
|
||||
def test_create_container_binary_string_error(self):
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
service.image = lambda: {'Id': 'abc123'}
|
||||
|
||||
self.mock_client.create_container.side_effect = APIError(None,
|
||||
None,
|
||||
b"Test binary string explanation")
|
||||
with pytest.raises(OperationFailedError) as ex:
|
||||
service.create_container()
|
||||
|
||||
assert ex.value.msg == "Cannot create container for service foo: Test binary string explanation"
|
||||
|
||||
def test_start_binary_string_error(self):
|
||||
service = Service('foo', client=self.mock_client)
|
||||
container = Container(self.mock_client, {'Id': 'abc123'})
|
||||
|
||||
self.mock_client.start.side_effect = APIError(None,
|
||||
None,
|
||||
b"Test binary string explanation with "
|
||||
b"driver failed programming external "
|
||||
b"connectivity")
|
||||
with mock.patch('compose.service.log', autospec=True) as mock_log:
|
||||
with pytest.raises(OperationFailedError) as ex:
|
||||
service.start_container(container)
|
||||
|
||||
assert ex.value.msg == "Cannot start service foo: " \
|
||||
"Test binary string explanation " \
|
||||
"with driver failed programming external connectivity"
|
||||
mock_log.warn.assert_called_once_with("Host is already in use by another container")
|
||||
|
||||
def test_ensure_image_exists_no_build(self):
|
||||
service = Service('foo', client=self.mock_client, build={'context': '.'})
|
||||
|
||||
Reference in New Issue
Block a user