Compare commits

...

339 Commits

Author SHA1 Message Date
Ulysses Souza
e9f9a1e9e1 Merge pull request #7155 from docker/bump-1.25.2-rc1
Bump 1.25.2-rc1
2020-01-17 20:13:44 +01:00
Ulysses Souza
634eb501f8 "Bump 1.25.2-rc1"
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-17 19:43:30 +01:00
Ulysses Souza
6286beb321 Merge pull request #7152 from docker/bump-pyinstaller
Bump pyinstaller to 3.6
2020-01-17 18:33:24 +01:00
Ulysses Souza
f0e5926ea7 Merge pull request #6950 from benthorner/master
Add "--attach-dependencies" to command "up" for attaching to dependencies
2020-01-16 18:10:25 +01:00
Ben Thorner
a6b602d086 Support attaching to dependencies on up
When using the 'up' command, only services listed as arguments are
attached to, which can be very different to the 'no argument' case
if a service has many and deep dependencies:

   - It's not clear when dependencies have failed to start. Have to run
'compose ps' separately to find out.
   - It's not clear when dependencies are erroring. Have to run 'compose
logs' separately to find out.

With a simple setup, it's possible to work around theses issue by
using the 'up' command without arguments. But when there are lots of
'top-level' services, with common dependencies, in a single config,
using 'up' without arguments isn't practical due to resource limits
and the sheer volume of output from other services.

This introduces a new '--attach-dependencies' flag to optionally attach
dependent containers as part of the 'up' command. This makes their logs
visible in the output, alongside the listed services. It also means we
benefit from the '--abort-on-container-exit' behaviour when dependencies
fail to start, giving more visibility of the failure.

Signed-off-by: Ben Thorner <ben.thorner@digital.cabinet-office.gov.uk>
2020-01-16 13:41:54 +00:00
Ulysses Souza
387f5e4c96 Bump pyinstaller to 3.6
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-16 13:46:47 +01:00
yukihira1992
53d00f7677 Refactored mutable default values.
Signed-off-by: yukihira1992 <ykhr0130@gmail.com>
2020-01-15 11:16:24 +01:00
Christopher Crone
a2cdffeeee Bump Linux dependencies
- Alpine 3.10.3
- Debian Stretch 20191118
- Python 3.7.5

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2020-01-15 10:54:57 +01:00
Christopher Crone
a92a8eb508 Bump macOS dependencies
- Python 3.7.5
- OpenSSL 1.1.1d

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2020-01-15 10:54:57 +01:00
Ulysses Souza
d1ef7c41aa Merge pull request #7140 from docker/dependabot/pip/cached-property-1.5.1
Bump cached-property from 1.3.0 to 1.5.1
2020-01-14 19:50:31 +01:00
Ulysses Souza
78dc92246f Merge pull request #7142 from docker/dependabot/pip/ipaddress-1.0.23
Bump ipaddress from 1.0.18 to 1.0.23
2020-01-14 18:51:15 +01:00
dependabot-preview[bot]
dafece4ae5 Bump cached-property from 1.3.0 to 1.5.1
Bumps [cached-property](https://github.com/pydanny/cached-property) from 1.3.0 to 1.5.1.
- [Release notes](https://github.com/pydanny/cached-property/releases)
- [Changelog](https://github.com/pydanny/cached-property/blob/master/HISTORY.rst)
- [Commits](https://github.com/pydanny/cached-property/compare/1.3.0...1.5.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-14 17:26:05 +00:00
Ulysses Souza
f15e54ab1b Merge pull request #7090 from docker/dependabot/pip/urllib3-1.25.7
Bump urllib3 from 1.24.2 to 1.25.7
2020-01-14 18:25:49 +01:00
Ulysses Souza
0e36e9f3eb Merge pull request #7141 from docker/dependabot/pip/coverage-5.0.3
Bump coverage from 4.5.4 to 5.0.3
2020-01-14 18:25:20 +01:00
Ulysses Souza
71e166e3bd Merge pull request #7139 from docker/dependabot/pip/certifi-2019.11.28
Bump certifi from 2017.4.17 to 2019.11.28
2020-01-14 18:24:58 +01:00
dependabot-preview[bot]
120a7b1b06 Bump ipaddress from 1.0.18 to 1.0.23
Bumps [ipaddress](https://github.com/phihag/ipaddress) from 1.0.18 to 1.0.23.
- [Release notes](https://github.com/phihag/ipaddress/releases)
- [Commits](https://github.com/phihag/ipaddress/compare/v1.0.18...v1.0.23)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-14 17:23:07 +00:00
Ulysses Souza
4b332453db Merge pull request #7144 from docker/dependabot/pip/paramiko-2.7.1
Bump paramiko from 2.6.0 to 2.7.1
2020-01-14 18:21:39 +01:00
Ulysses Souza
d87e19c14b Merge pull request #7027 from kiniou/compatibility-option-from-env
Allow compatibility option with `COMPOSE_COMPATIBILITY` environment variable
2020-01-13 19:28:48 +01:00
Kevin Roy
093cc2c089 Allow setting compatibility options from environment
Signed-off-by: Kevin Roy <kiniou@gmail.com>
2020-01-13 14:53:03 +01:00
dependabot-preview[bot]
661afb4003 Bump paramiko from 2.6.0 to 2.7.1
Bumps [paramiko](https://github.com/paramiko/paramiko) from 2.6.0 to 2.7.1.
- [Release notes](https://github.com/paramiko/paramiko/releases)
- [Changelog](https://github.com/paramiko/paramiko/blob/master/NEWS)
- [Commits](https://github.com/paramiko/paramiko/compare/2.6.0...2.7.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-13 13:34:32 +00:00
dependabot-preview[bot]
2cdd2f626b Bump coverage from 4.5.4 to 5.0.3
Bumps [coverage](https://github.com/nedbat/coveragepy) from 4.5.4 to 5.0.3.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-4.5.4...coverage-5.0.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-13 13:33:13 +00:00
dependabot-preview[bot]
707a340304 Bump certifi from 2017.4.17 to 2019.11.28
Bumps [certifi](https://github.com/certifi/python-certifi) from 2017.4.17 to 2019.11.28.
- [Release notes](https://github.com/certifi/python-certifi/releases)
- [Commits](https://github.com/certifi/python-certifi/compare/2017.04.17...2019.11.28)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-13 13:32:31 +00:00
Ulysses Souza
f1cfd93c8f Merge pull request #7096 from docker/dependabot/pip/pytest-5.3.2
Bump pytest from 3.6.3 to 5.3.2
2020-01-10 17:47:09 +01:00
dependabot-preview[bot]
3ea84fd9bc Bump pytest from 3.6.3 to 5.3.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 3.6.3 to 5.3.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/3.6.3...5.3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-10 16:10:59 +00:00
Ulysses Souza
2cb1b4bd5b Merge pull request #6873 from frenzymadness/pytest_compatibility
Bump Pytest and add refactor compatibility with new version
2020-01-10 17:09:33 +01:00
Lumir Balhar
a436fb953c Remove indentation from test YAML
Signed-off-by: Lumir Balhar <lbalhar@redhat.com>
2020-01-10 08:41:11 +01:00
Ulysses Souza
26f1aeff15 Merge pull request #7054 from docker/dependabot/pip/jsonschema-3.2.0
Bump jsonschema from 3.0.1 to 3.2.0
2020-01-09 15:30:05 +01:00
Sergey Fursov
c818bfc62c support PyYAML up to 5.x version
Signed-off-by: Sergey Fursov <geyser85@gmail.com>
2020-01-09 12:30:51 +01:00
Lumir Balhar
73cc89c15f Use stdlib modules instead of deprecated pytest fixtures
Signed-off-by: Lumír Balhar <lbalhar@redhat.com>
2020-01-09 07:01:44 +01:00
Lumir Balhar
60458c8ae7 Implement custom context manager for changing CWD
Signed-off-by: Lumír Balhar <lbalhar@redhat.com>
2020-01-09 06:55:28 +01:00
Lumir Balhar
fb14f41ddb Move to the latest pytest versions for Python 2 and 3
Signed-off-by: Lumír Balhar <lbalhar@redhat.com>
2020-01-09 06:55:28 +01:00
Sebastiaan van Stijn
33eeef41ab Remove "bundle" subcommand and support for DAB files
Deploying stacks using the "Docker Application Bundle" (`.dab`) file
format was introduced as an experimental feature in Docker 1.13 /
17.03, but superseded by support for Docker Compose files in the CLI.

With no development being done on this feature, and no active use of the file
format, support for the DAB file format and the top-level `docker deploy` command
(hidden by default in 19.03), will be removed from the CLI, in favour of
`docker stack deploy` using compose files.

This patch removes the `docker-compose bundle` subcommand from Docker Compose,
which was used to convert compose files into DAB files (and given the above,
will no longer be needed).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-01-08 16:42:49 +01:00
dependabot-preview[bot]
4ace98acbe Bump jsonschema from 3.0.1 to 3.2.0
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 3.0.1 to 3.2.0.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v3.0.1...v3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 15:01:58 +00:00
Ulysses Souza
36790fc0e8 Merge pull request #7058 from docker/dependabot/pip/idna-2.8
Bump idna from 2.5 to 2.8
2020-01-08 16:00:45 +01:00
Ulysses Souza
23d663a84e Merge pull request #7059 from docker/dependabot/pip/pysocks-1.7.1
Bump pysocks from 1.6.7 to 1.7.1
2020-01-08 15:58:00 +01:00
dependabot-preview[bot]
81e3566ebd Bump urllib3 from 1.24.2 to 1.25.7
Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.24.2 to 1.25.7.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/master/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/1.24.2...1.25.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 14:42:12 +00:00
Ulysses Souza
bd0ec191bd Merge pull request #7092 from docker/dependabot/pip/colorama-0.4.3
Bump colorama from 0.4.0 to 0.4.3
2020-01-08 15:41:40 +01:00
Ulysses Souza
d27ecf694c Merge pull request #7111 from docker/dependabot/pip/websocket-client-0.57.0
Bump websocket-client from 0.32.0 to 0.57.0
2020-01-08 15:40:54 +01:00
Ulysses Souza
bc90b7badf Merge pull request #7077 from docker/dependabot/pip/ddt-1.2.2
Bump ddt from 1.2.0 to 1.2.2
2020-01-08 15:35:38 +01:00
Ulysses Souza
702dd9406c Merge pull request #7093 from ulyssessouza/warn-invalid-version
Validate version format on formats 2+
2020-01-08 10:47:01 +01:00
Ulysses Souza
704ee56553 Merge pull request #7122 from ndeloof/shutil
Don't adjust output on terminal width when piped into another command
2020-01-08 10:46:03 +01:00
dependabot-preview[bot]
f2f6b30350 Bump websocket-client from 0.32.0 to 0.57.0
Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 0.32.0 to 0.57.0.
- [Release notes](https://github.com/websocket-client/websocket-client/releases)
- [Changelog](https://github.com/websocket-client/websocket-client/blob/master/ChangeLog)
- [Commits](https://github.com/websocket-client/websocket-client/compare/v0.32.0...v0.57.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 09:17:12 +00:00
dependabot-preview[bot]
75c45c27df Bump pysocks from 1.6.7 to 1.7.1
Bumps [pysocks](https://github.com/Anorov/PySocks) from 1.6.7 to 1.7.1.
- [Release notes](https://github.com/Anorov/PySocks/releases)
- [Changelog](https://github.com/Anorov/PySocks/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Anorov/PySocks/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-08 09:17:04 +00:00
Nicolas De Loof
31396786ba publish package on PyPI
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
d6c13b69c3 compute sha256sum
windows nodes don't have openssl installed:'(

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
0e826efee5 attempt to fix windows build
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
1af3852277 Generate changelog
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
9c6db546e8 Remove Circle-CI and AppVeyor config files
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
417d72ea3d Compute checksum
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
bdb11849b1 Use .Jenkinsfile extension for IDE support
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
da55677154 Release pipeline
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
7be66baaa7 TAG and BUILD_TAG are obsolete
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
6b0acc9ecb tests don't run in parallel
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
8859ab0d66 Use gotemplate formater to extract specific data
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
9478725a70 Fix tested docker releases in Pipeline
This allows Engine team to trigger a compose build by pushing a PR
changing the `dockerVersions` variable to test Release Candidates

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
2955f48468 Get docker versions using a plain command line
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
644c55c4f7 Use declarative syntax when possible
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
912d90832c Use a simple script to get docker-ce releases
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
c5c287db5c We don't use FOSSA anymore
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
dd889b990b Prepare drop of python 2.x support
see https://github.com/docker/compose/issues/6890

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 10:15:48 +01:00
Nicolas De Loof
3df4ba1544 Assume infinite terminal width when not running in a terminal
Close https://github.com/docker/compose/issues/7119

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2020-01-08 08:40:18 +01:00
ulyssessouza
7f49bbb998 Validate version format on formats 2+
Signed-off-by: ulyssessouza <ulyssessouza@gmail.com>
2020-01-07 18:37:47 +01:00
Ulysses Souza
9f373b0b86 Merge pull request #7128 from docker/post-release-1.25.1
Post release 1.25.1
2020-01-07 17:20:41 +01:00
Ulysses Souza
67cce913a6 Set dev version to 1.26.0dev after releasing 1.25.1
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-07 16:44:42 +01:00
Ulysses Souza
cc93c97689 Merge pull request #7123 from docker/bump-1.25.1
Bump 1.25.1
2020-01-06 19:08:18 +01:00
Ulysses Souza
a82fef0722 "Bump 1.25.1"
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-06 17:42:50 +01:00
Ulysses Souza
f70b8c9a53 Merge remote-tracking branch 'upstream/release' into bump-1.25.1 2020-01-06 17:17:07 +01:00
Ulysses Souza
b572a1e2e0 Merge pull request #7121 from ulyssessouza/fix_binary_string_error_treatment
Fix binary string error treatment
2020-01-06 16:56:30 +01:00
Ulysses Souza
37eb7a509b Decode APIError explanation to unicode before usage
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-06 16:00:34 +01:00
Ulysses Souza
cba8ad474c Fix by adding an assert to make the comparison effective
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-01-06 15:53:32 +01:00
dependabot-preview[bot]
025002260b Bump colorama from 0.4.0 to 0.4.3
Bumps [colorama](https://github.com/tartley/colorama) from 0.4.0 to 0.4.3.
- [Release notes](https://github.com/tartley/colorama/releases)
- [Changelog](https://github.com/tartley/colorama/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tartley/colorama/compare/0.4.0...0.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-09 13:31:00 +00:00
dependabot-preview[bot]
e6e9263260 Bump ddt from 1.2.0 to 1.2.2
Bumps [ddt](https://github.com/datadriventests/ddt) from 1.2.0 to 1.2.2.
- [Release notes](https://github.com/datadriventests/ddt/releases)
- [Commits](https://github.com/datadriventests/ddt/compare/1.2.0...1.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 07:10:30 +00:00
dependabot-preview[bot]
e9220f45df Bump coverage from 4.4.2 to 4.5.4
Bumps [coverage](https://github.com/nedbat/coveragepy) from 4.4.2 to 4.5.4.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/coverage-4.4.2...coverage-4.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 08:09:10 +01:00
dependabot-preview[bot]
780a425c60 Bump flake8 from 3.5.0 to 3.7.9
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.5.0 to 3.7.9.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.5.0...3.7.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 08:09:07 +01:00
dependabot-preview[bot]
d32b9f95ca Bump pytest-cov from 2.5.1 to 2.8.1
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.5.1 to 2.8.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.5.1...v2.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-04 08:08:54 +01:00
Ulysses Souza
a23f39127e Merge pull request #7071 from docker/bump-1.25.1-rc1
Bump 1.25.1-rc1
2019-11-29 20:15:40 +01:00
Ulysses Souza
d92e9beec1 "Bump 1.25.1-rc1"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-29 19:21:16 +01:00
Ulysses Souza
8ebd7f96f0 Merge pull request #7070 from docker/macos-folder-build
Build fixes for macOS
2019-11-29 19:16:41 +01:00
Christopher Crone
b7a675b1c0 Upload macOS folder format to bintray
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-11-29 18:28:47 +01:00
Christopher Crone
8820343882 Stash all macOS build artifacts
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-11-29 18:28:17 +01:00
Christopher Crone
fedc8f71ad Build single binary and folder format for macOS
Previously we were overwriting the single binary with the folder
format.

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-11-29 18:27:39 +01:00
Ulysses Souza
e82d38f333 Merge pull request #7052 from ndeloof/pull_can_build
Report image we can't pull and must be built
2019-11-29 15:48:38 +01:00
Christopher Crone
d6b5d324e2 Use Python3 for macOS build environment
With the deprecation of Python 2 coming soon, explicitly use
Python 3.

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-11-28 20:26:58 +01:00
Ulysses Souza
44edd65065 Merge pull request #7009 from glance-/shellcheck
Resolve shellcheck warnings in container-script
2019-11-28 13:37:50 +01:00
Nicolas De Loof
55c5c8e8ac Report image we can't pull and must be built
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-25 15:18:27 +01:00
dependabot-preview[bot]
101ee1cd62 Bump idna from 2.5 to 2.8
Bumps [idna](https://github.com/kjd/idna) from 2.5 to 2.8.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst)
- [Commits](https://github.com/kjd/idna/compare/v2.5...v2.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-25 13:27:05 +00:00
Ulysses Souza
517efbf386 Merge pull request #7005 from glance-/HOME-in-container
Pass in HOME env-var in container mode.
2019-11-22 17:02:07 +01:00
Anton Lundin
c8cfc590cc Better userns detection in container-script
This uses formatting to have docker info just emit the information we're interested in.

Based-on-code-by: Sebastiaan van Stijn <github@gone.​nl>
Signed-off-by: Anton Lundin <anton.lundin@umu.se>

Co-Authored-By: Sebastiaan van Stijn <thaJeztah@users.noreply.github.com>
2019-11-22 16:24:09 +01:00
Ulysses Souza
a7e8356651 Update maintainers and add CODEOWNERS for github
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-22 16:00:07 +01:00
Ulysses Souza
332fa8bf62 Merge pull request #7010 from ndeloof/catalina
Build OSX binary as a directory
2019-11-22 15:26:09 +01:00
Ulysses Souza
a83d86e7ce Merge pull request #7037 from ndeloof/stdin
config_detail.filename is None when passed by stdin
2019-11-22 15:24:43 +01:00
Ulysses Souza
1de8205996 Merge pull request #7048 from ulyssessouza/update-dev-version
Update dev version to 1.26.0dev
2019-11-22 14:15:09 +01:00
Ulysses Souza
d837d27ad7 Update dev version
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-22 14:13:50 +01:00
Ulysses Souza
cfc131b502 Merge pull request #7042 from ulyssessouza/release
Sync backport changes in release 1.25.0
2019-11-22 14:10:42 +01:00
Nicolas De Loof
e6ec77047b Revert "only pull images that can't build"
This reverts commit c6dd7da15e.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-21 14:37:41 +01:00
Ulysses Souza
f4cf7a939e Announce drop py2
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-21 13:23:56 +01:00
Nicolas De Loof
fa9e8bd641 Skip label if some config file was passed by stdin
com.docker.compose.project.config_files must contain valid file paths

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-21 09:59:22 +01:00
Nicolas De Loof
e13a7213f1 Build OSX binary as a directory
OSX Catalina otherwise do scan the temporary executable files created by the single-file packaging.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-21 09:01:41 +01:00
Nicolas De Loof
fe2b692547 testcase for compose file read from stdin
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-20 15:38:15 +01:00
Nicolas De Loof
962421d019 config_detail.filename is None when passed by stdin
Fix #7032

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-11-20 09:00:47 +01:00
Ulysses Souza
4038169d96 Merge pull request #7028 from docker/bump-1.25.0
Bump 1.25.0
2019-11-18 22:56:24 +01:00
Ulysses Souza
b42d4197ce Add latest tag question on resume and start to tag on build
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-18 22:46:12 +01:00
Ulysses Souza
0a186604be "Bump 1.25.0"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-18 19:35:34 +01:00
Ulysses Souza
d072601197 "Bump 1.25.0"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-18 19:29:40 +01:00
Ulysses Souza
a0592ce585 "Bump 1.25.0"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-18 19:14:13 +01:00
Ulysses Souza
c49678a11f Merge remote-tracking branch 'upstream/release' into bump-1.25.0 2019-11-18 18:28:25 +01:00
Ulysses Souza
2887d82d16 Merge pull request #6982 from smamessier/fix_non_ascii_error
Fixed non-ascii error when using COMPOSE_DOCKER_CLI_BUILD=1 for Buildkit
2019-11-18 16:45:04 +01:00
Ulysses Souza
2919bebea4 Fix non ascii chars error. Python2 only
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-11-18 15:43:50 +01:00
Anton Lundin
aeddfd41d6 Resolve shellcheck warnings in container-script
This fixes a couple of small potential issues pointed out by shellcheck.

Signed-off-by: Anton Lundin <anton.lundin@umu.se>
2019-11-07 21:55:03 +01:00
Djordje Lukic
5478c966f1 Merge pull request #7008 from zelahi/fix-readme-link
Fixed broken README link for common use cases
2019-11-07 09:59:49 +01:00
Zuhayr Elahi
e546533cfe Fixed broken README link for common use cases
Signed-off-by: Zuhayr Elahi <elahi.zuhayr@gmail.com>
2019-11-06 17:10:48 -08:00
Jean-Christophe Sirot
abef11b2a6 Merge pull request #6996 from ajlai/fix-color-order-and-remove-red
Make container service color deterministic, remove red from chosen colors
2019-11-06 16:11:57 +01:00
Anton Lundin
b9a4581d60 Pass in HOME env-var in container mode.
To get ~/-paths to work as expected in contaier mode, env-var HOME must
be the same outside the container as inside the docker-compose
container, otherwise HOME inside the container points to /root which
might not be what the user expects.

Signed-off-by: Anton Lundin <anton.lundin@umu.se>
2019-11-06 13:05:58 +01:00
Anthony Lai
802fa20228 Make container service color deterministic, remove red from chosen colors
Signed-off-by: Anthony Lai <anthonyjlai@gmail.com>
2019-11-03 23:44:31 +00:00
Djordje Lukic
fa34ee7362 Merge pull request #6973 from glours/set_no_color_if_clicolor_defined_to_0
Set no-colors to true if CLICOLOR env variable is set to 0
2019-10-31 16:45:10 +01:00
Sebastien Mamessier
a3a23bf949 Fixed error when using startswith on non-ascii string
Signed-off-by: Sebastien Mamessier <smamessier@uber.com>
2019-10-30 13:57:08 +01:00
Djordje Lukic
f6b6cd22df Merge pull request #6987 from docker/bump-1.25.0-rc4
Bump 1.25.0-rc4
2019-10-28 16:54:32 +01:00
Djordje Lukic
8f3c9c58c5 "Bump 1.25.0-rc4"
Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-10-28 16:18:12 +01:00
Djordje Lukic
52c3e94be0 Merge remote-tracking branch 'origin/release' into bump-1.25.0-rc4 2019-10-28 16:16:58 +01:00
Jean-Christophe Sirot
cfc48f2c13 Merge pull request #6986 from rumpl/fix-unit-test-close-fd
Cleanup all open files
2019-10-28 16:07:18 +01:00
Djordje Lukic
f8142a899c Cleanup all open files
If the fd is not closed the cleanup will fail on windows.

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-10-28 15:36:05 +01:00
Djordje Lukic
ea22d5821c Merge pull request #6984 from docker/bump-1.25.0-rc3
Bump 1.25.0-rc3
2019-10-28 12:13:11 +01:00
Djordje Lukic
c7e82489f4 "Bump 1.25.0-rc3"
Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-10-28 11:33:59 +01:00
Djordje Lukic
952340043a Merge remote-tracking branch 'origin/release' into bump-1.25.0-rc3 2019-10-28 11:24:06 +01:00
Guillaume Lours
2e7493a889 Set no-colors to true if CLICOLOR env variable is set to 0
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-21 11:37:46 +02:00
Jean-Christophe Sirot
4be2fa010a Merge pull request #6972 from glours/align_image_size_display_to_docker_cli
Format image size as decimal to be align with Docker CLI
2019-10-18 15:26:15 +02:00
Guillaume Lours
386bdda246 Format image size as decimal to be align with Docker CLI
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-18 12:50:38 +02:00
okor
17bbbba7d6 update docker-py
Signed-off-by: Jason Ormand <jason.ormand1@gmail.com>
2019-10-18 09:37:24 +02:00
Nicolas De Loof
1ca10f90fb Fix acceptance tests
tty is now (correclty) reported to have 80 columns, which split service
ID in two lines

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-10-16 14:31:27 +02:00
Nicolas De Loof
452880af7c Use python Posix support to get tty size
stty is not portable outside *nix
Note: shutil.get_terminal_size require python 3.3

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-10-16 14:31:27 +02:00
Guillaume LOURS
944660048d Merge pull request #6964 from guillaumerose/addmorelabels
Add working dir, config files and env file in service labels
2019-10-15 10:06:42 +02:00
Guillaume Rose
dbe4d7323e Add working dir, config files and env file in service labels
Signed-off-by: Guillaume Rose <guillaume.rose@docker.com>
2019-10-15 09:18:09 +02:00
Guillaume Rose
1678a4fbe4 Run CI on amd64
Signed-off-by: Guillaume Rose <guillaume.rose@docker.com>
2019-10-14 22:01:04 +02:00
Guillaume LOURS
4e83bafec6 Merge pull request #6955 from ndeloof/paramiko
Bump paramiko to 2.6.0
2019-10-10 10:59:44 +02:00
Nicolas De Loof
8973a940e6 Bump paramiko to 2.6.0
close #6953

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2019-10-10 08:55:15 +02:00
Zuhayr Elahi
8835056ce4 UPDATED log message
Signed-off-by: Zuhayr Elahi <elahi.zuhayr@gmail.com>
2019-10-10 07:08:42 +02:00
Zuhayr Elahi
3135a0a839 Added log message to check compose file
Signed-off-by: Zuhayr Elahi <elahi.zuhayr@gmail.com>
2019-10-10 07:08:42 +02:00
Guillaume Lours
cdae06a89c exclude issue flagged with kind/feature from stale process
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-09 21:51:34 +02:00
Guillaume Lours
79bf9ed652 correct invalid yaml indentation
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-09 21:10:18 +02:00
Nicolas De loof
29af1a84ca Merge pull request #6952 from glours/stale_configuration
Add config file for @probot/stale
2019-10-09 16:41:58 +02:00
Guillaume Lours
9375c15bad Add config file for @probot/stale
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-09 16:16:57 +02:00
Chris Crone
8ebb1a6f19 Merge pull request #6949 from jcsirot/fix-pushbin-script-verbosity
Remove set -x to make this script less verbose
2019-10-09 12:04:24 +02:00
Jean-Christophe Sirot
37be2ad9cd Remove set -x to make this script less verbose
Signed-off-by: Jean-Christophe Sirot <jean-christophe.sirot@docker.com>
2019-10-09 10:51:17 +02:00
Nicolas De loof
6fe35498a5 Add dependencies for ARM build (#6908)
Add dependencies for ARM build
2019-10-09 09:38:58 +02:00
Stefan Scherer
ce52f597a0 Enhance build script for different CPU architectures
Signed-off-by: Stefan Scherer <stefan.scherer@docker.com>
2019-10-09 09:11:29 +02:00
Stefan Scherer
79f29dda23 Add dependencies for ARM build
Signed-off-by: Stefan Scherer <scherer_stefan@icloud.com>
2019-10-09 09:11:29 +02:00
Nicolas De loof
7172849913 Fix "extends" same file optimization (#6425)
Fix "extends" same file optimization
2019-10-09 08:50:54 +02:00
Aleksandr Mezin
c24b7b6464 Fix same file 'extends' optimization
Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
2019-10-09 11:36:17 +06:00
Aleksandr Mezin
74f892de95 Add test to verify same file 'extends' optimization
Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
2019-10-09 11:36:17 +06:00
Nicolas De loof
09acc5febf [TAR-995] ADDED a stage for executing License Scans (#6875)
[TAR-995] ADDED a stage for executing License Scans
2019-10-08 16:25:28 +02:00
Nicolas De loof
1f16a7929d Merge pull request #6864 from samueljsb/formatter_class
Change Formatter.table method to staticmethod
2019-10-08 16:24:40 +02:00
Nicolas De loof
f9113202e8 Add automatic labeling of bug, feature & question issues (#6944)
Add automatic labeling of bug, feature & question issues
2019-10-08 16:23:15 +02:00
Nicolas De loof
5f2161cad9 Merge pull request #6912 from cranzy/fixing_broken_link
Fixing features broken link
2019-10-08 16:19:31 +02:00
Guillaume LOURS
70f8e38b1d Add automatic labeling of bug, feature & question issues
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2019-10-08 11:07:04 +02:00
Ulysses Souza
186aa6e5c3 Merge pull request #6914 from lukas9393/6913-progress-arg
Fix --progress arg when run docker-compose build
2019-10-07 12:28:49 +02:00
Guillaume LOURS
bc57a1bd54 Merge pull request #6925 from ulyssessouza/fix-secrets-warning-message
Fix secret missing warning
2019-09-27 10:51:37 +02:00
ulyssessouza
eca358e2f0 Fix secret missing warning
Signed-off-by: ulyssessouza <ulyssessouza@gmail.com>
2019-09-27 09:10:49 +02:00
Lukas Hettwer
32ac6edb86 Fix --progress arg when run docker-compose build
--progress is no longer processed as flag but as argument with value.

Signed-off-by: Lukas Hettwer <lukas.hettwer@aboutyou.de>

Resolve: [#6913]
2019-09-24 16:02:12 +02:00
Dimitar Dimitrov
475f8199f7 Fixing features broken link
Signed-off-by: Dimitar Dimitrov <dimitar.dimitrov@docker.com>
2019-09-24 13:31:30 +03:00
Zuhayr Elahi
98d7cc8d0c ADDED a stage for executing License Scans
Signed-off-by: Zuhayr Elahi <elahi.zuhayr@gmail.com>
2019-09-13 14:25:06 -07:00
Ulysses Souza
d7c7e21921 Merge pull request #6131 from sagarafr/fix-5920-missing-secret-message
Add a warning message to secret file
2019-09-09 17:45:08 +02:00
Ulysses Souza
70ead597d2 Add tests to 'get_secret' warnings
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-09-09 10:04:05 +02:00
Marian Gappa
b9092cacdb Fix missing secret error message
Add a warning message when the secret file doesn't exist

Fixes #5920

Signed-off-by: Marian Gappa <marian.gappa@gmail.com>
2019-09-09 10:04:05 +02:00
Silvin Lubecki
1566930a70 Merge pull request #6862 from deathtracktor/master
Fix KeyError when remote network labels are None.
2019-09-06 11:13:48 +02:00
Danil Kister
a5fbf91b72 Prevent KeyError when remote network labels are None.
Signed-off-by: Danil Kister <danil.kister@gmail.com>
2019-09-05 21:36:10 +02:00
Ulysses Souza
ecf03fe280 Merge pull request #6882 from ulyssessouza/fix_attach_restarting_container
Fix race condition on watch_events
2019-09-05 16:46:14 +02:00
Ulysses Souza
47d170b06a Fix race condition on watch_events
Avoid to attach to restarting containers and ignore
race conditions when trying to attach to already
dead containers

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-09-04 17:55:05 +02:00
Chris Crone
9973f051ba Merge pull request #6878 from ulyssessouza/bump-debian
Bump runtime debian
2019-08-30 16:42:56 +02:00
Ulysses Souza
2199278b44 Merge pull request #6865 from ulyssessouza/support-cli-build
Add support to CLI build
2019-08-30 13:46:21 +02:00
Ulysses Souza
5add9192ac Rename envvar switch to COMPOSE_DOCKER_CLI_BUILD
From `COMPOSE_NATIVE_BUILDER` to `COMPOSE_DOCKER_CLI_BUILD`

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-30 12:11:09 +02:00
Ulysses Souza
0c6fce271e Bump runtime debian
From `stretch-20190708-slim` to `stretch-20190812-slim`

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-29 17:45:21 +02:00
Ulysses Souza
9d7ad3bac1 Add comment on native build and fix typo
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-29 16:30:50 +02:00
Nao YONASHIRO
719a1b0581 fix: use subprocess32 for python2
Signed-off-by: Nao YONASHIRO <yonashiro@r.recruit.co.jp>
2019-08-29 14:21:19 +02:00
Ulysses Souza
bbdb3cab88 Add integration tests to native builder
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-29 09:31:16 +02:00
Ulysses Souza
ee8ca5d6f8 Rephrase warnings when building with the cli
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-28 17:24:15 +02:00
Nao YONASHIRO
15e8edca3c feat: add a warning if someone uses the --compress or --parallel flag
Signed-off-by: Nao YONASHIRO <yonashiro@r.recruit.co.jp>
2019-08-28 17:24:15 +02:00
Nao YONASHIRO
81e223d499 feat: add --progress flag
Signed-off-by: Nao YONASHIRO <yonashiro@r.recruit.co.jp>
2019-08-28 17:24:14 +02:00
Nao YONASHIRO
862a13b8f3 fix: add build flags
Signed-off-by: Nao YONASHIRO <yonashiro@r.recruit.co.jp>
2019-08-28 17:24:14 +02:00
Nao YONASHIRO
cacbcccc0c Add support to CLI build
This includes can be enabled by setting the env var
`COMPOSE_NATIVE_BUILDER=1`.

Signed-off-by: Nao YONASHIRO <yonashiro@r.recruit.co.jp>

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-28 17:24:14 +02:00
Samuel Searles-Bryant
672ced8742 Change Formatter.table method to staticmethod
Make this a staticmethod so it's easier to use without needing to init a
Formatter object first.

Signed-off-by: Samuel Searles-Bryant <samuel.searles-bryant@unipart.io>
2019-08-22 14:25:15 +01:00
Djordje Lukic
4cfa622de8 Merge pull request #6631 from chibby0ne/update_jsonschema_dependency
requirements: update jsonschema dependency
2019-08-22 12:54:48 +02:00
Ulysses Souza
525bc9ef7a Merge pull request #6856 from aiordache/bump-alpine
update alpine version to 3.10.1
2019-08-21 15:49:14 +02:00
aiordache
60dcf87cc0 update alpine version to 3.10.1
Signed-off-by: aiordache <anca.iordache@docker.com>
2019-08-20 12:10:26 +02:00
Ulysses Souza
2c668e237d Merge pull request #6835 from docker/bump-1.25.0-rc2
Bump 1.25.0-rc2
2019-08-07 15:03:32 +02:00
Ulysses Souza
661ac20e5d "Bump 1.25.0-rc2"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-08-06 15:28:46 +02:00
Ulysses Souza
ab93b87f04 Merge remote-tracking branch 'upstream/release' into bump-1.25.0-rc2 2019-08-06 15:05:08 +02:00
Jean-Christophe Sirot
cf3c07d6ee Merge pull request #6826 from ulyssessouza/env_override_integration_test
Add integration tests regarding environment
2019-07-31 14:15:53 +02:00
Ulysses Souza
b03889ac2a Add integration tests regarding environment
This covers what was included in #6800

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-31 02:09:41 +02:00
Antonio Gutierrez
66856e884c requirements: update jsonschema dependency
Fixes: https://github.com/docker/compose/issues/6347

Signed-off-by: Antonio Gutierrez <chibby0ne@gmail.com>
2019-07-27 21:43:40 +02:00
Djordje Lukic
7a7c9ff67a Merge pull request #6800 from KlaasH/revise-env-file-option
Make '--env-file' option top-level only and fix failure with subcommands
2019-07-25 12:15:11 +02:00
Klaas Hoekema
413e5db7b3 Add shell completions for --env-file option
Adds completions for the --env-file toplevel option to the bash, fish,
and zsh completions files.

Signed-off-by: Klaas Hoekema <khoekema@azavea.com>
2019-07-24 09:25:10 -04:00
Klaas Hoekema
69c0683bfe Pass toplevel_environment to run_one_off_container
Instead of passing `project_dir` from `TopLevelCommand.run` to
`run_one_off_container` then using it there to load the toplevel
environment (duplicating the logic that `TopLevelCommand.toplevel_environment`
encapsulates), pass the Environment object.

Signed-off-by: Klaas Hoekema <khoekema@azavea.com>
2019-07-24 09:25:10 -04:00
Klaas Hoekema
088a798e7a Fix typo in 'split_env' error message
Signed-off-by: Klaas Hoekema <khoekema@azavea.com>
2019-07-24 09:25:10 -04:00
Klaas Hoekema
35eb40424c Call TopLevelCommand's environment 'toplevel_environment'
To help prevent confusion between the different meanings and sources
of "environment", rename the method that loads the environment from
the .env or --env-file (i.e. the one that applies at a project level)
to 'toplevel_environment'.

Signed-off-by: Klaas Hoekema <khoekema@azavea.com>
2019-07-24 09:25:05 -04:00
Klaas Hoekema
99464d9c2b Handle environment file override within TopLevelCommand
Several (but not all) of the subcommands are accepting and processing the
`--env-file` option, but only because they need to look for a specific
value in the environment. The work of applying the override makes more
sense as the domain of TopLevelCommand, and moving it there and removing
the option from the subcommands makes things simpler.

Signed-off-by: Klaas Hoekema <khoekema@azavea.com>
2019-07-24 09:24:06 -04:00
Silvin Lubecki
cd8e2f870f Merge pull request #6813 from ulyssessouza/fix_stdin_open
Fix stdin_open when running docker-compose run
2019-07-24 11:20:20 +02:00
Ulysses Souza
c641ea08ae Fix stdin_open when running docker-compose run
This fix makes sure that stdin_open specified in the service
is considering when shelling out to the CLI

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-22 17:27:10 +02:00
Jean-Christophe Sirot
d285ba6aee Merge pull request #6803 from ulyssessouza/pin-image-tags
Pin test images on a non rolling tag
2019-07-19 16:35:22 +02:00
Ulysses Souza
cd098e0cad Pin test images on a non rolling tag
Mainly busybox:latest to the current latest which is 1.31.0-uclibc

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-18 11:10:37 +02:00
Djordje Lukic
d212fe68a6 Merge pull request #6728 from albers/completion-config--no-interpolate
Add bash completion for `config --no-interpolate`
2019-07-16 11:59:18 +02:00
Djordje Lukic
c8279bc4db Merge pull request #6738 from Inconnu08/set-optimization
Replace sets with set literal syntax for efficiency
2019-07-15 15:23:24 +02:00
Djordje Lukic
61aa2e346e Merge pull request #6797 from chris-crone/macos-bump-python-3.7.4
Bump macOS build dependency
2019-07-15 10:33:45 +02:00
Djordje Lukic
98932e9cb4 Merge pull request #6754 from Goryudyuma/6740-fix-display
fix: The correct number is displayed
2019-07-15 10:30:59 +02:00
Goryudyuma
59491c7d77 add: test for units
Signed-off-by: Kei Matsumoto <umaretekyoumade@gmail.com>
2019-07-14 04:31:16 +09:00
Kei Matsumoto
75d41edb94 fix: Add test
Signed-off-by: Kei Matsumoto <umaretekyoumade@gmail.com>
2019-07-14 03:38:29 +09:00
Goryudyuma
f9099c91ae fix: The correct number is displayed
Signed-off-by: Kei Matsumoto <umaretekyoumade@gmail.com>
2019-07-14 03:38:12 +09:00
Ulysses Souza
1b326fce57 Merge pull request #6720 from ijc/pass-env-to-docker-cli
Pass environment when calling through to docker cli.
2019-07-12 10:11:47 +02:00
Ulysses Souza
ca721728f6 Merge pull request #6588 from javabrett/6587-default-mand-interp-err
Default ?err to (missing) required VAR name. Fixed #6587.
2019-07-11 17:17:46 +02:00
Ulysses Souza
2e31ebba6a Merge pull request #6798 from chris-crone/linux-bump-deps
Bump Linux build dependencies
2019-07-11 16:09:58 +02:00
Christopher Crone
993bada521 Bump Linux build dependencies
* Python 3.7.2 to 3.7.4
* Docker 18.09.5 to 18.09.7
* Alpine 3.9.3 to 3.10.0
* Debian stretch-20190326 to stretch-20190708

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-07-10 17:32:13 +02:00
Christopher Crone
b0e7d801a3 Bump macOS build dependency
* Python 3.7.3 to 3.7.4

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-07-10 17:03:45 +02:00
Chris Crone
7258edb75d Merge pull request #6793 from chris-crone/bump-openssl-1.1.1c-python-3.7.3
Bump macOS build dependencies
2019-07-08 18:42:35 +02:00
Ulysses Souza
f9d1075a5d Merge pull request #6792 from ulyssessouza/bump-texttable
Bump texttable from 0.9.1 to 1.6.2
2019-07-08 15:23:31 +02:00
Ulysses Souza
a1c9d4925a Merge pull request #6791 from ulyssessouza/bump-mock
Bump mock from 2.0.0 to 3.0.5
2019-07-08 15:23:22 +02:00
Christopher Crone
3d80c8e86d Bump macOS build dependencies
* OpenSSL 1.1.1a to 1.1.1c
* Python 3.7.2 to 3.7.3

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-07-08 15:05:10 +02:00
Ulysses Souza
0bfa1c34f0 Bump texttable from 0.9.1 to 1.6.2
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-08 14:52:30 +02:00
Ulysses Souza
57a2bb0c50 Bump mock from 2.0.0 to 3.0.5
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-08 13:47:19 +02:00
Ulysses Souza
3d693f3733 Merge pull request #6778 from ulyssessouza/cleanup-setup_py-versioning
Strip up generic versions and bump requests
2019-07-03 17:31:15 +02:00
Ulysses Souza
ce5451c5b4 Strip up generic versions and bump requests
Replaces generic limitations with a next major value
Bump the minimal `requests` to 2.20.0

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-02 15:49:07 +02:00
Ulysses Souza
df2e833cf0 Merge pull request #6777 from ulyssessouza/pin-busybox-image-version
Pin busybox image version in tests
2019-07-02 14:33:56 +02:00
Ulysses Souza
cacc9752a3 Pin busybox image version in tests
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-07-02 13:42:41 +02:00
Djordje Lukic
85d940909e Merge pull request #6766 from docker/bump-1.24.1
Bump 1.24.1
2019-06-24 12:15:25 +02:00
Djordje Lukic
4667896b69 "Bump 1.24.1"
Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-06-24 11:20:44 +02:00
Djordje Lukic
a78e3b0c7c Bump docker-py
Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-06-24 10:38:39 +02:00
Dave Tucker
5e7521909d Add .fossa.yml file
This commit adds a .fossa.yml file used by fossa.io
It allows for fossa to scan the dependencies and figure out which oss
licenses are in use. This can be added to CI at some point in the near
future.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
2019-06-24 10:38:38 +02:00
Djordje Lukic
272e85dce3 Merge remote-tracking branch 'origin/release' into bump-1.24.1 2019-06-24 10:38:25 +02:00
Eli Uriegas
cf419dce4c Add .fossa.yml file (#6750)
Add .fossa.yml file
2019-06-17 10:23:44 -07:00
Dave Tucker
8c387c6013 Add .fossa.yml file
This commit adds a .fossa.yml file used by fossa.io
It allows for fossa to scan the dependencies and figure out which oss
licenses are in use. This can be added to CI at some point in the near
future.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
2019-06-14 14:58:17 +01:00
Inconnu08
57055e0e66 Replace sets with set literal syntax for efficiency
Signed-off-by: Taufiq Rahman <taufiqrx8@gmail.com>
2019-06-02 20:21:21 +06:00
Inconnu08
c37fb783fe replace sets with set literal syntax for efficiency
Signed-off-by: Taufiq Rahman <taufiqrx8@gmail.com>
2019-06-01 01:31:35 +06:00
Inconnu08
b29b6a1538 replace sets with set literal syntax for efficiency
Signed-off-by: Taufiq Rahman <taufiqrx8@gmail.com>
2019-05-31 20:29:09 +06:00
Harald Albers
d68113f5c0 Add bash completion for config --no-interpolate
Signed-off-by: Harald Albers <github@albersweb.de>
2019-05-24 21:59:14 +02:00
Ulysses Souza
2bc4161526 Merge pull request #6726 from docker/bump-1.25.0-rc1
Bump 1.25.0-rc1
2019-05-24 00:33:04 +02:00
Ulysses Souza
8552e8e283 "Bump 1.25.0-rc1"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-23 23:39:09 +02:00
Ulysses Souza
3803d35c03 Merge remote-tracking branch 'upstream/release' into bump-1.25.0-rc1 2019-05-23 23:38:30 +02:00
Ulysses Souza
26e1a2dd31 Merge pull request #6725 from ulyssessouza/fix-release-script
Fix release script get_full_version()
2019-05-23 23:37:06 +02:00
Ulysses Souza
1f55b533c4 Fix release script get_full_version()
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-23 23:35:57 +02:00
Brett Randall
fb4d5aa7e6 Include required but missing VAR name and assignment in interpolation error message.
Error message format is now e.g.:

ERROR: Missing mandatory value for "environment" option interpolating ['MYENV=${MYVAR:?}'] in service "myservice":

Fixed #6587.

Signed-off-by: Brett Randall <javabrett@gmail.com>
2019-05-24 07:01:39 +10:00
Ulysses Souza
e806520dc3 Merge pull request #6723 from ulyssessouza/fix-reorder-imports
Fix imports ordering
2019-05-23 22:04:50 +02:00
Ulysses Souza
a2516c48d9 Fix imports ordering
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-23 22:04:02 +02:00
Ulysses Souza
79639af394 Merge pull request #6721 from ulyssessouza/fix-release-finalize
Fix 'finalize' command on release script
2019-05-23 21:39:40 +02:00
Ulysses Souza
2d2b0bd9a8 Fix 'finalize' command on release script
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-23 21:38:20 +02:00
Ian Campbell
9d2508cf58 Pass environment when calling through to docker cli.
This ensures that settings from any `.env` file (such as `DOCKER_HOST`) are
passed on to the cli.

Unit tests are adjusted for the new parameter and a new case is added to ensure
it is propagated as expected.

Fixes: 6661

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-05-23 16:29:46 +01:00
Ulysses Souza
e1baa90f6b Merge pull request #6719 from ulyssessouza/fix-release-script
Fix release script for null user
2019-05-22 19:01:01 +02:00
Ulysses Souza
c15e8af7f8 Fix release script for null user
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-22 19:00:16 +02:00
Ulysses Souza
4218b46c78 Merge pull request #6666 from joakimr-axis/armpurge
Purge Dockerfile.armhf which is no longer needed
2019-05-22 16:27:09 +02:00
Ulysses Souza
81258f59db Merge pull request #6715 from ulyssessouza/bump-dockerpy-401
Bump docker-py 4.0.1
2019-05-22 14:11:07 +02:00
Ulysses Souza
e4b4babc24 Bump docker-py 4.0.1
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-22 11:55:37 +02:00
Ian Campbell
f764faa841 Merge pull request #6649 from GeyseR/requests_upgrade
support requests up to 2.22.0 version
2019-05-21 13:36:31 +01:00
Sergey Fursov
a857be3f7e support requests up to 2.22.x version
Signed-off-by: Sergey Fursov <geyser85@gmail.com>
2019-05-21 14:50:17 +03:00
Ian Campbell
a89128118b Merge pull request #6342 from collin5/b5547
--remove-orphans is ignored when using up --no-start
2019-05-20 15:45:24 +01:00
Ian Campbell
263d18ce93 Merge pull request #6624 from orisano/feat-empty-cache-from
feat: drop empty tag on cache_from
2019-05-20 15:35:48 +01:00
Nao YONASHIRO
51ee6093df feat: drop empty tag on cache_from
Signed-off-by: Nao YONASHIRO <owan.orisano@gmail.com>
2019-05-20 23:32:15 +09:00
Ulysses Souza
9de6ec3700 Merge pull request #6695 from Inconnu08/fix_depreciation
fixes warn method is deprecated
2019-05-20 12:34:51 +02:00
Inconnu08
99e67d0c06 fix warning method is deprecated with tests
Signed-off-by: Taufiq Rahman <taufiqrx8@gmail.com>
2019-05-15 23:46:12 +06:00
Ulysses Souza
75d5eb0108 Merge pull request #6707 from ulyssessouza/clean-containers-before-rm
Remove remaining containers on test_build_run
2019-05-15 11:44:37 +02:00
Ulysses Souza
8a9575bd0d Remove remaining containers on test_build_run
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-05-14 19:13:21 +02:00
Ulysses Souza
b612361541 Merge pull request #6654 from jkldgoefgkljefogeg/master
fix #6579 cli ps --all
2019-05-14 11:53:04 +02:00
noname
c2783d6f88 fix #6579 cli ps --all
Signed-off-by: Seedf <github_commit@nohdmi.com>
2019-05-13 18:56:43 -07:00
Ulysses Souza
a5b13f369d Merge pull request #6700 from ulyssessouza/bump_urllib3
Bump urllib3
2019-05-13 14:07:21 +02:00
ulyssessouza
3a47000e71 Bump urllib3
Signed-off-by: ulyssessouza <ulysses.souza@docker.com>
2019-05-12 13:33:38 +02:00
Joakim Roubert
482bca9519 Purge Dockerfile.armhf which is no longer needed
Current Dockerfile builds fine for armhf and thus the outdated
Dockerfile.armhf is unnecessary.

Change-Id: Idafdb9fbddedd622c2c0aaddb1d5331d81cfe57d
Signed-off-by: Joakim Roubert <joakimr@axis.com>
2019-04-23 09:53:42 +02:00
Djordje Lukic
79557e3d3a Merge pull request #6657 from ulyssessouza/skip_race_condition_test
Avoid race condition on test
2019-04-19 16:37:14 +02:00
Ulysses Souza
f2dc923084 Avoid race condition on test
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-04-19 15:53:02 +02:00
Ulysses Souza
8a89d94e15 Merge pull request #6641 from ulyssessouza/dockerfiles_refactor
Refactor Dockerfiles for generating musl binaries
2019-04-19 11:46:41 +02:00
Ulysses Souza
e047169315 Workaround race conditions on tests
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-04-17 17:59:12 +02:00
Ulysses Souza
2b24eb693c Refactor release and build scripts
- Make use of the same Dockerfile when producing
an image for testing and for deploying to
DockerHub

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-04-17 16:08:33 +02:00
Ulysses Souza
c217bab7f6 Refactor Dockerfiles for generating musl binaries
- Refactor Dockerfile to be used for tests and distribution on docker hub on debian and alpine
to use for final usage and also tests
- Adapt test scripts to the new Dockerfiles' structure
- Adapt Jenkinsfile to add alpine to the test matrix

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-04-17 16:08:33 +02:00
Ulysses Souza
5265f63c34 Merge pull request #6632 from ulyssessouza/update-releasedocs
Update release process on updating docs
2019-04-04 15:05:49 +02:00
Ulysses Souza
9e3d9f6681 Update release process on updating docs
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-04-04 11:51:12 +02:00
Ulysses Souza
41c8df39fe Merge pull request #6618 from ulyssessouza/bump-1.24.0-changelog
Bump 1.24.0 changelog on master
2019-03-29 14:38:20 +01:00
Djordje Lukic
ef10c1803f "Bump 1.24.0"
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-28 19:38:25 +01:00
Djordje Lukic
ada945c5cd Merge pull request #6615 from ulyssessouza/bump-docker-py-3.7.2
Bump docker-py 3.7.2
2019-03-28 18:15:30 +01:00
Ulysses Souza
ac148bc1ca Bump docker-py 3.7.2
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-28 17:45:03 +01:00
Ian Campbell
e84ffb6aeb Merge pull request #6592 from treatwell/6589-depends_on-recreation-fix
Fixed depends_on recreation behaviour for issue #6589
2019-03-26 14:06:14 +00:00
joeweoj
8a339946fa Fixed depends_on recreation behaviour for issue #6589
Previously any containers which did *not* have any links were always recreated.
In order to fix depends_on and preserve expected links recreation behaviour, we now only use the ConvergenceStrategy.always recreation strategy for a service if any of the the following conditions are true:
* --always-recreate-deps flag provided
* service container is stopped
* service defines links but the container does not have any
* container has links but the service definition does not

Signed-off-by: joeweoj <joewardell@gmail.com>
2019-03-26 11:48:20 +00:00
Ulysses Souza
b2723d6b3d Merge pull request #6610 from ulyssessouza/fix-httperror-no-attribute-message
Fix script for the case of release file already present on pypi
2019-03-25 17:18:59 +01:00
Ian Campbell
6ccbb56fec Merge pull request #6494 from collin5/b6464
Only pull images that can't build `docker-compose pull`
2019-03-25 13:25:32 +00:00
Collins Abitekaniza
c6dd7da15e only pull images that can't build
Signed-off-by: Collins Abitekaniza <abtcolns@gmail.com>
2019-03-24 01:05:30 +03:00
Ulysses Souza
154d7c1722 Fix script for release file already present case
This avoids a:
"AttributeError: 'HTTPError' object has no attribute 'message'"

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-22 17:14:18 +01:00
Ulysses Souza
fc757fb4f5 Merge pull request #6604 from ulyssessouza/fix-release-resources
Fix release resources
2019-03-22 11:52:36 +01:00
Ulysses Souza
2948c396a6 Fix bintray docker-compose link
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-22 11:23:44 +01:00
Ulysses Souza
15f8c30a51 Fix typo on finalize
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-22 11:23:44 +01:00
Ulysses Souza
cd1fcd3ea5 Use os.system() instead of run_setup()
Use `os.system()` instead of `run_setup()` because the last
is not taking any effect

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-22 11:23:36 +01:00
Ulysses Souza
1e4fde8aa7 Bump docker-py version to 3.7.1
This docker-py version includes ssh fixes

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-22 11:22:11 +01:00
Ulysses Souza
a27448bdab Merge pull request #6594 from ulyssessouza/bump-docker-py-to-3.7.1
Bump docker-py version to 3.7.1
2019-03-21 10:30:54 +01:00
Ulysses Souza
dc712bfa23 Bump docker-py version to 3.7.1
This docker-py version includes ssh fixes

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-03-20 18:03:41 +01:00
Chris Crone
3b846ac8de Merge pull request #6578 from bfirsh/bootloader-ignore-signals
Enable bootloader_ignore_signals in pyinstaller
2019-03-15 11:48:33 +01:00
Ben Firshman
0863785e96 Enable bootloader_ignore_signals in pyinstaller
Fixes #3347

Signed-off-by: Ben Firshman <ben@firshman.co.uk>
2019-03-12 12:25:35 -04:00
Ian Campbell
c6c57fcf49 Merge pull request #6518 from ulyssessouza/bump-python-37
Bump python 3.6.8 -> 3.7.2
2019-03-08 12:05:55 +00:00
Ian Campbell
733b827f85 Merge pull request #6544 from CatEars/secrets-added-after-container
Add test and implementation for secret added after container has been…
2019-03-08 11:21:00 +00:00
Henke Adolfsson
853215acf6 Remove project.stop() in test
Signed-off-by: Henke Adolfsson <catears13@gmail.com>
2019-03-08 07:43:53 +01:00
Henke Adolfsson
87935893fc Update data for unit tests
Signed-off-by: Henke Adolfsson <catears13@gmail.com>
2019-03-08 07:43:53 +01:00
Henke Adolfsson
aa79fb2473 Ensure test passes
Signed-off-by: Henke Adolfsson <catears13@gmail.com>
2019-03-08 07:43:53 +01:00
Henke Adolfsson
76d0406fab Add test and implementation for secret added after container has been created
The issue is that if a secret is added to the compose file, then it will
not notice that containers have diverged since last run, because secrets
are not part of the config_hash, which determines if the configuration of
a service is the same or not.

Signed-off-by: Henke Adolfsson <catears13@gmail.com>
2019-03-08 07:43:53 +01:00
Chris Crone
a1f3cb6d89 Merge pull request #6546 from ijc/update-docs-branch
docs/README.md: update since `vnext-compose` branch is no longer used.
2019-03-07 20:31:43 +01:00
Ian Campbell
7bf9963cd6 Merge pull request #6547 from kudos/bugfix/scale-zero-default
Fix scale attribute to accept 0 as a value
2019-03-07 15:40:14 +00:00
Michael Irwin
d8e390eb9f Added test case to verify fix for #6525
Signed-off-by: Michael Irwin <mikesir87@gmail.com>
2019-03-07 15:30:11 +01:00
Michael Irwin
3f1d41a97e Fix merging of compose files when network has None config
Signed-off-by: Michael Irwin <mikesir87@gmail.com>

Resolves #6525
2019-03-07 15:30:11 +01:00
Jonathan Cremin
087bef4f95 Add tests for compose file 'scale: 0'
Signed-off-by: Jonathan Cremin <jonathan@crem.in>
2019-03-06 12:57:14 +00:00
Ian Campbell
0b039202ac docs/README.md: update since vnext-compose branch is no longer used.
All PRs should be made to `master` now. Also:

- Template seems to exist now[0] so remove the "coming soon".
- The labels used seem different now, but labelling seems more like a docs
  maintainer thing than a contributor thing, so just drop that paragraph.

[0] https://raw.githubusercontent.com/docker/docker.github.io/master/.github/PULL_REQUEST_TEMPLATE.md

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-06 10:37:32 +00:00
Ian Campbell
40b0ce3e5d Merge pull request #6542 from akshitgrover/6028-Add_Quiet_Builds
Add --quiet build flag
2019-03-05 14:55:32 +00:00
Jonathan Cremin
42c965935f Fix scale attribute to accept 0 as a value
Signed-off-by: Jonathan Cremin <jonathan@crem.in>
2019-03-05 11:34:48 +00:00
Ian Campbell
615c01c50a Merge pull request #6368 from xificurC/master
adds --no-interpolate to docker-compose config
2019-03-05 09:38:36 +00:00
Peter Nagy (NPE)
e34d329227 adds --no-interpolate to docker-compose config
Signed-off-by: Peter Nagy <pnagy@gratex.com>
2019-03-04 13:03:35 +01:00
Akshit Grover
1f97a572fe Add --quiet build flag
Signed-off-by: Akshit Grover <akshit.grover2016@gmail.com>
2019-03-02 13:07:23 +05:30
slowr
b09d8802ed Added additional argument (--env-file) for docker-compose to import environment variables from a given PATH.
Signed-off-by: Dimitrios Mavrommatis <jim.mavrommatis@gmail.com>
2019-02-26 16:38:54 +01:00
tuttieee
572032fc0b Fix Project#build_container_operation_with_timeout_func not to mutate a 'option' dict over multiple containers
Signed-off-by: Yuichiro Tsuchiya <t.yic.yt@gmail.com>
2019-02-25 13:07:41 +01:00
Christopher Crone
133df63108 Add built Python smoke test to macOS setup script
Prior to this smoke test, the macOS setup step wouldn't fail if the
Python that it built wasn't functional. This will make debugging Python
build issues easier in the future.

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-21 16:21:09 +01:00
Christopher Crone
dbc229dc37 Fix macOS build for Python 3.7
- Specify --with-openssl directory for Python build
- Better checks for downloaded SDK, OpenSSL, and Python
- Fix missing slash for Python build CPPFLAGS

Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-21 13:57:25 +01:00
Ulysses Souza
bb0bd3b26b Harmonize tox and virtualenv versions
- Set all tox versions to 2.9.1
- Set all virtualenv version to 16.2.0

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-02-21 13:56:45 +01:00
Ulysses Souza
a734371e7f Bump python version from 3.6.8 to 3.7.2
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-02-21 13:56:45 +01:00
Chris Crone
768c788da9 Merge pull request #6504 from docker/mac-bump-openssl
Bump OpenSSL for macOS build
2019-02-21 11:50:24 +01:00
Ulysses Souza
aee88e21bf Merge pull request #6529 from ulyssessouza/rm-option
Add --no-rm to command build
2019-02-20 18:33:29 +01:00
Ulysses Souza
a35aef4953 Add --no-rm to command build
- When present, build does not remove
intermediate containers after a successful build.

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-02-20 18:09:09 +01:00
Christopher Crone
fbbf78d3da macOS: Bump OpenSSL to 1.1.1a
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-20 15:59:41 +01:00
Chris Crone
a65b3cd758 Merge pull request #6503 from docker/mac-virtualenv-fix
Force virtualenv version for macOS CI
2019-02-20 15:59:13 +01:00
Chris Crone
4813689c9e Merge pull request #6514 from albers/completion-fix-build--memory
Fix bash completion for `build --memory`
2019-02-20 15:48:15 +01:00
Harald Albers
436a343a18 Fix bash completion for build --memory
- the option requires an argument
- adds missing short form `-m`

Signed-off-by: Harald Albers <github@albersweb.de>
2019-02-11 13:50:41 +01:00
Christopher Crone
d9ffec4002 circleci: Fix virtualenv version to 16.2.0
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-05 12:13:19 +01:00
Chris Crone
3cddd1b670 Merge pull request #6501 from chris-crone/build-fixes
Various build fixes
2019-02-05 11:41:29 +01:00
Ulysses Souza
c8a621b637 Fix Flake8 lint
This removes extra indentation and replace the use of `is` by `==` when
comparing strings

Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-02-05 11:11:52 +01:00
Christopher Crone
f472fd545b Dockerfile: Force version of virtualenv to 16.2.0
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-05 10:51:33 +01:00
Christopher Crone
f1f0894c1b script.build.linux: Do not tail image build logs
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-05 10:50:55 +01:00
Christopher Crone
b572b32999 requirements-dev: Fix version of mock to 2.0.0
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-05 10:50:25 +01:00
Christopher Crone
8ad4c08109 macOS: Bump Python and OpenSSL
Signed-off-by: Christopher Crone <christopher.crone@docker.com>
2019-02-05 10:40:03 +01:00
Collins Abitekaniza
c27132afad remove stopped containers on --remove-orphans
Signed-off-by: Collins Abitekaniza <abtcolns@gmail.com>

kill orphan containers, catch APIError Exception

Signed-off-by: Collins Abitekaniza <abtcolns@gmail.com>

test remove orphans with --no-start

Signed-off-by: Collins Abitekaniza <abtcolns@gmail.com>
2019-01-25 14:28:56 +03:00
Ulysses Souza
9de1f569f3 Merge pull request #6479 from ulyssessouza/shell-completion-parallel
Add `--parallel` to `docker build`'s options in `bash` and `zsh` completion
2019-01-24 15:10:06 +01:00
Ulysses Souza
698ea33b15 Add --parallel to docker build's options in bash and zsh completion
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2019-01-21 19:13:45 +01:00
Ulysses Domiciano Souza
f158fb03e7 Merge pull request #6364 from ulyssessouza/6350-avoid-warning-on-exec
Avoids misleading warning concerning env vars when perfoming an `exec` command
2019-01-21 12:01:31 +01:00
Chris Crone
8f5f7e72be Merge pull request #6466 from rumpl/credential-spec
Support for credential_spec
2019-01-21 11:03:34 +01:00
Chris Crone
718346f103 Merge pull request #6454 from rumpl/digest-distribution
Resolve digests without pulling image
2019-01-21 11:02:42 +01:00
Djordje Lukic
ae0f3c74a0 Support for credential_spec
Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-01-17 16:00:22 +01:00
Chris Crone
e40eaa5df6 Merge pull request #6461 from albers/completion-ps--all
Add bash completion for `ps --all|-a`
2019-01-16 22:08:35 +01:00
Djordje Lukic
0c20fc5d91 Resolve digests without pulling image
If there is no image locally `docker-compose --resolve-image-digests`
will try and get the digest from the repository.

Fixes https://github.com/docker/compose/issues/5818

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
2019-01-15 14:24:26 +01:00
Chris Crone
d5d49a8e29 Merge pull request #6460 from shin-/maintainers_update
Update maintainers file
2019-01-15 12:56:21 +01:00
Harald Albers
14a1a0c020 Add bash completion for ps --all|-a
Signed-off-by: Harald Albers <github@albersweb.de>
2019-01-15 09:01:49 +01:00
Joffrey F
6933435004 Update maintainers file
Signed-off-by: Joffrey F <joffrey@docker.com>
2019-01-14 15:22:12 -08:00
Ulysses Souza
f4ed9b2ef5 Detects the execution on anexec command and sets the environment to silent mode.
Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
2018-12-28 02:43:41 +01:00
159 changed files with 3356 additions and 1711 deletions

View File

@@ -1,63 +0,0 @@
version: 2
jobs:
test:
macos:
xcode: "9.4.1"
steps:
- checkout
- run:
name: setup script
command: ./script/setup/osx
- run:
name: install tox
command: sudo pip install --upgrade tox==2.1.1 virtualenv==16.2.0
- run:
name: unit tests
command: tox -e py27,py36,py37 -- tests/unit
build-osx-binary:
macos:
xcode: "9.4.1"
steps:
- checkout
- run:
name: upgrade python tools
command: sudo pip install --upgrade pip virtualenv==16.2.0
- run:
name: setup script
command: DEPLOYMENT_TARGET=10.11 ./script/setup/osx
- run:
name: build script
command: ./script/build/osx
- store_artifacts:
path: dist/docker-compose-Darwin-x86_64
destination: docker-compose-Darwin-x86_64
- deploy:
name: Deploy binary to bintray
command: |
OS_NAME=Darwin PKG_NAME=osx ./script/circle/bintray-deploy.sh
build-linux-binary:
machine:
enabled: true
steps:
- checkout
- run:
name: build Linux binary
command: ./script/build/linux
- store_artifacts:
path: dist/docker-compose-Linux-x86_64
destination: docker-compose-Linux-x86_64
- deploy:
name: Deploy binary to bintray
command: |
OS_NAME=Linux PKG_NAME=linux ./script/circle/bintray-deploy.sh
workflows:
version: 2
all:
jobs:
- test
- build-linux-binary
- build-osx-binary

View File

@@ -11,3 +11,4 @@ docs/_site
.tox
**/__pycache__
*.pyc
Jenkinsfile

14
.fossa.yml Normal file
View File

@@ -0,0 +1,14 @@
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
# Visit https://fossa.io to learn more
version: 2
cli:
server: https://app.fossa.io
fetcher: custom
project: git@github.com:docker/compose
analyze:
modules:
- name: .
type: pip
target: .
path: .

6
.github/CODEOWNERS vendored Normal file
View 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

View File

@@ -1,6 +1,9 @@
---
name: Bug report
about: Report a bug encountered while using docker-compose
title: ''
labels: kind/bug
assignees: ''
---

View File

@@ -1,6 +1,9 @@
---
name: Feature request
about: Suggest an idea to improve Compose
title: ''
labels: kind/feature
assignees: ''
---

View File

@@ -1,6 +1,9 @@
---
name: Question about using Compose
about: This is not the appropriate channel
title: ''
labels: kind/question
assignees: ''
---

59
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 180
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- kind/feature
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: true
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when removing the stale label.
unmarkComment: >
This issue has been automatically marked as not stale anymore due to the recent activity.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue has been automatically closed because it had not recent activity during the stale period.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed

View File

@@ -1,7 +1,172 @@
Change log
==========
1.24.0 (2019-03-22)
1.25.2 (2020-01-17)
-------------------
### Features
- Allow compatibility option with `COMPOSE_COMPATIBILITY` environment variable
- Bump PyInstaller from 3.5 to 3.6
- Bump pysocks from 1.6.7 to 1.7.1
- Bump websocket-client from 0.32.0 to 0.57.0
- Bump urllib3 from 1.24.2 to 1.25.7
- Bump jsonschema from 3.0.1 to 3.2.0
- Bump PyYAML from 4.2b1 to 5.3
- Bump certifi from 2017.4.17 to 2019.11.28
- Bump coverage from 4.5.4 to 5.0.3
- Bump paramiko from 2.6.0 to 2.7.1
- Bump cached-property from 1.3.0 to 1.5.1
- Bump minor Linux and MacOSX dependencies
### Bugfixes
- Validate version format on formats 2+
- Assume infinite terminal width when not running in a terminal
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)
-------------------
### Features

View File

@@ -1,36 +1,74 @@
FROM docker:18.06.1 as docker
FROM python:3.6
ARG DOCKER_VERSION=19.03.5
ARG PYTHON_VERSION=3.7.5
ARG BUILD_ALPINE_VERSION=3.10
ARG BUILD_DEBIAN_VERSION=slim-stretch
ARG RUNTIME_ALPINE_VERSION=3.10.3
ARG RUNTIME_DEBIAN_VERSION=stretch-20191118-slim
RUN set -ex; \
apt-get update -qq; \
apt-get install -y \
locales \
python-dev \
git
ARG BUILD_PLATFORM=alpine
COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
FROM docker:${DOCKER_VERSION} AS docker-cli
# Python3 requires a valid locale
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
FROM python:${PYTHON_VERSION}-alpine${BUILD_ALPINE_VERSION} AS build-alpine
RUN apk add --no-cache \
bash \
build-base \
ca-certificates \
curl \
gcc \
git \
libc-dev \
libffi-dev \
libgcc \
make \
musl-dev \
openssl \
openssl-dev \
python2 \
python2-dev \
zlib-dev
ENV BUILD_BOOTLOADER=1
RUN useradd -d /home/user -m -s /bin/bash user
FROM python:${PYTHON_VERSION}-${BUILD_DEBIAN_VERSION} AS build-debian
RUN apt-get update && apt-get install --no-install-recommends -y \
curl \
gcc \
git \
libc-dev \
libffi-dev \
libgcc-6-dev \
libssl-dev \
make \
openssl \
python2.7-dev \
zlib1g-dev
FROM build-${BUILD_PLATFORM} AS build
COPY docker-compose-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["sh", "/usr/local/bin/docker-compose-entrypoint.sh"]
COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
WORKDIR /code/
# FIXME(chris-crone): virtualenv 16.3.0 breaks build, force 16.2.0 until fixed
RUN pip install virtualenv==16.2.0
RUN pip install tox==2.1.1
RUN pip install tox==2.9.1
ADD requirements.txt /code/
ADD requirements-dev.txt /code/
ADD .pre-commit-config.yaml /code/
ADD setup.py /code/
ADD tox.ini /code/
ADD compose /code/compose/
ADD README.md /code/
COPY requirements.txt .
COPY requirements-dev.txt .
COPY .pre-commit-config.yaml .
COPY tox.ini .
COPY setup.py .
COPY README.md .
COPY compose compose/
RUN tox --notest
COPY . .
ARG GIT_COMMIT=unknown
ENV DOCKER_COMPOSE_GITSHA=$GIT_COMMIT
RUN script/build/linux-entrypoint
ADD . /code/
RUN chown -R user /code/
ENTRYPOINT ["/code/.tox/py36/bin/docker-compose"]
FROM alpine:${RUNTIME_ALPINE_VERSION} AS runtime-alpine
FROM debian:${RUNTIME_DEBIAN_VERSION} AS runtime-debian
FROM runtime-${BUILD_PLATFORM} AS runtime
COPY docker-compose-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["sh", "/usr/local/bin/docker-compose-entrypoint.sh"]
COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
COPY --from=build /usr/local/bin/docker-compose /usr/local/bin/docker-compose

View File

@@ -1,39 +0,0 @@
FROM python:3.6
RUN set -ex; \
apt-get update -qq; \
apt-get install -y \
locales \
curl \
python-dev \
git
RUN curl -fsSL -o dockerbins.tgz "https://download.docker.com/linux/static/stable/armhf/docker-17.12.0-ce.tgz" && \
SHA256=f8de6378dad825b9fd5c3c2f949e791d22f918623c27a72c84fd6975a0e5d0a2; \
echo "${SHA256} dockerbins.tgz" | sha256sum -c - && \
tar xvf dockerbins.tgz docker/docker --strip-components 1 && \
mv docker /usr/local/bin/docker && \
chmod +x /usr/local/bin/docker && \
rm dockerbins.tgz
# Python3 requires a valid locale
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
RUN useradd -d /home/user -m -s /bin/bash user
WORKDIR /code/
RUN pip install tox==2.1.1
ADD requirements.txt /code/
ADD requirements-dev.txt /code/
ADD .pre-commit-config.yaml /code/
ADD setup.py /code/
ADD tox.ini /code/
ADD compose /code/compose/
RUN tox --notest
ADD . /code/
RUN chown -R user /code/
ENTRYPOINT ["/code/.tox/py36/bin/docker-compose"]

View File

@@ -1,19 +0,0 @@
FROM docker:18.06.1 as docker
FROM alpine:3.8
ENV GLIBC 2.28-r0
RUN apk update && apk add --no-cache openssl ca-certificates curl libgcc && \
curl -fsSL -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
curl -fsSL -o glibc-$GLIBC.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/$GLIBC/glibc-$GLIBC.apk && \
apk add --no-cache glibc-$GLIBC.apk && \
ln -s /lib/libz.so.1 /usr/glibc-compat/lib/ && \
ln -s /lib/libc.musl-x86_64.so.1 /usr/glibc-compat/lib && \
ln -s /usr/lib/libgcc_s.so.1 /usr/glibc-compat/lib && \
rm /etc/apk/keys/sgerrand.rsa.pub glibc-$GLIBC.apk && \
apk del curl
COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
COPY dist/docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
ENTRYPOINT ["docker-compose"]

View File

@@ -1,4 +1,4 @@
FROM s390x/alpine:3.6
FROM s390x/alpine:3.10.1
ARG COMPOSE_VERSION=1.16.1

170
Jenkinsfile vendored
View File

@@ -1,84 +1,112 @@
#!groovy
def image
def dockerVersions = ['19.03.5', '18.09.9']
def baseImages = ['alpine', 'debian']
def pythonVersions = ['py27', 'py37']
def buildImage = { ->
wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) {
stage("build image") {
checkout(scm)
def imageName = "dockerbuildbot/compose:${gitCommit()}"
image = docker.image(imageName)
try {
image.pull()
} catch (Exception exc) {
image = docker.build(imageName, ".")
image.push()
}
pipeline {
agent none
options {
skipDefaultCheckout(true)
buildDiscarder(logRotator(daysToKeepStr: '30'))
timeout(time: 2, unit: 'HOURS')
timestamps()
}
}
}
def get_versions = { int number ->
def docker_versions
wrappedNode(label: "ubuntu && !zfs") {
def result = sh(script: """docker run --rm \\
--entrypoint=/code/.tox/py27/bin/python \\
${image.id} \\
/code/script/test/versions.py -n ${number} docker/docker-ce recent
""", returnStdout: true
)
docker_versions = result.split()
}
return docker_versions
}
stages {
stage('Build test images') {
// TODO use declarative 1.5.0 `matrix` once available on CI
parallel {
stage('alpine') {
agent {
label 'ubuntu && amd64 && !zfs'
}
steps {
buildImage('alpine')
}
}
stage('debian') {
agent {
label 'ubuntu && amd64 && !zfs'
}
steps {
buildImage('debian')
}
}
}
}
stage('Test') {
steps {
// TODO use declarative 1.5.0 `matrix` once available on CI
script {
def testMatrix = [:]
baseImages.each { baseImage ->
dockerVersions.each { dockerVersion ->
pythonVersions.each { pythonVersion ->
testMatrix["${baseImage}_${dockerVersion}_${pythonVersion}"] = runTests(dockerVersion, pythonVersion, baseImage)
}
}
}
def runTests = { Map settings ->
def dockerVersions = settings.get("dockerVersions", null)
def pythonVersions = settings.get("pythonVersions", null)
if (!pythonVersions) {
throw new Exception("Need Python versions to test. e.g.: `runTests(pythonVersions: 'py27,py36')`")
}
if (!dockerVersions) {
throw new Exception("Need Docker versions to test. e.g.: `runTests(dockerVersions: 'all')`")
}
{ ->
wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) {
stage("test python=${pythonVersions} / docker=${dockerVersions}") {
checkout(scm)
def storageDriver = sh(script: 'docker info | awk -F \': \' \'$1 == "Storage Driver" { print $2; exit }\'', returnStdout: true).trim()
echo "Using local system's storage driver: ${storageDriver}"
sh """docker run \\
-t \\
--rm \\
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
-e "TAG=${image.id}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersions}" \\
-e "BUILD_NUMBER=\$BUILD_TAG" \\
-e "PY_TEST_VERSIONS=${pythonVersions}" \\
--entrypoint="script/test/ci" \\
${image.id} \\
--verbose
"""
}
parallel testMatrix
}
}
}
}
}
}
buildImage()
def testMatrix = [failFast: true]
def docker_versions = get_versions(2)
def buildImage(baseImage) {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
image = docker.image(imageName)
for (int i = 0; i < docker_versions.length; i++) {
def dockerVersion = docker_versions[i]
testMatrix["${dockerVersion}_py27"] = runTests([dockerVersions: dockerVersion, pythonVersions: "py27"])
testMatrix["${dockerVersion}_py36"] = runTests([dockerVersions: dockerVersion, pythonVersions: "py36"])
testMatrix["${dockerVersion}_py37"] = runTests([dockerVersions: dockerVersion, pythonVersions: "py37"])
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
try {
image.pull()
} catch (Exception exc) {
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--target build \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT}" \\
.\\
"""
sh "docker push ${imageName}"
}
echo "${imageName}"
return imageName
}
}
}
parallel(testMatrix)
def runTests(dockerVersion, pythonVersion, baseImage) {
return {
stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
node("ubuntu && amd64 && !zfs") {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def storageDriver = sh(script: "docker info -f \'{{.Driver}}\'", returnStdout: true).trim()
echo "Using local system's storage driver: ${storageDriver}"
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
sh """docker run \\
-t \\
--rm \\
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersion}" \\
-e "BUILD_NUMBER=${env.BUILD_NUMBER}" \\
-e "PY_TEST_VERSIONS=${pythonVersion}" \\
--entrypoint="script/test/ci" \\
${imageName} \\
--verbose
"""
}
}
}
}
}

View File

@@ -11,9 +11,9 @@
[Org]
[Org."Core maintainers"]
people = [
"mefyl",
"mnottale",
"shin-",
"ndeloof",
"rumpl",
"ulyssessouza",
]
[Org.Alumni]
people = [
@@ -34,6 +34,10 @@
# including muti-file support, variable interpolation, secrets
# emulation and many more
"dnephin",
"shin-",
"mefyl",
"mnottale",
]
[people]
@@ -74,7 +78,22 @@
Email = "mazz@houseofmnowster.com"
GitHub = "mnowster"
[People.shin-]
[people.ndeloof]
Name = "Nicolas De Loof"
Email = "nicolas.deloof@gmail.com"
GitHub = "ndeloof"
[people.rumpl]
Name = "Djordje Lukic"
Email = "djordje.lukic@docker.com"
GitHub = "rumpl"
[people.shin-]
Name = "Joffrey F"
Email = "joffrey@docker.com"
Email = "f.joffrey@gmail.com"
GitHub = "shin-"
[people.ulyssessouza]
Name = "Ulysses Domiciano Souza"
Email = "ulysses.souza@docker.com"
GitHub = "ulyssessouza"

View File

@@ -2,15 +2,17 @@ Docker Compose
==============
![Docker Compose](logo.png?raw=true "Docker Compose Logo")
## :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
from your configuration. To learn more about all the features of Compose
see [the list of features](https://github.com/docker/docker.github.io/blob/master/compose/overview.md#features).
see [the list of features](https://github.com/docker/docker.github.io/blob/master/compose/index.md#features).
Compose is great for development, testing, and staging environments, as well as
CI workflows. You can learn more about each case in
[Common Use Cases](https://github.com/docker/docker.github.io/blob/master/compose/overview.md#common-use-cases).
[Common Use Cases](https://github.com/docker/docker.github.io/blob/master/compose/index.md#common-use-cases).
Using Compose is basically a three-step process.

315
Release.Jenkinsfile Normal file
View File

@@ -0,0 +1,315 @@
#!groovy
def dockerVersions = ['19.03.5', '18.09.9']
def baseImages = ['alpine', 'debian']
def pythonVersions = ['py27', 'py37']
pipeline {
agent none
options {
skipDefaultCheckout(true)
buildDiscarder(logRotator(daysToKeepStr: '30'))
timeout(time: 2, unit: 'HOURS')
timestamps()
}
stages {
stage('Build test images') {
// TODO use declarative 1.5.0 `matrix` once available on CI
parallel {
stage('alpine') {
agent {
label 'linux'
}
steps {
buildImage('alpine')
}
}
stage('debian') {
agent {
label 'linux'
}
steps {
buildImage('debian')
}
}
}
}
stage('Test') {
steps {
// TODO use declarative 1.5.0 `matrix` once available on CI
script {
def testMatrix = [:]
baseImages.each { baseImage ->
dockerVersions.each { dockerVersion ->
pythonVersions.each { pythonVersion ->
testMatrix["${baseImage}_${dockerVersion}_${pythonVersion}"] = runTests(dockerVersion, pythonVersion, baseImage)
}
}
}
parallel testMatrix
}
}
}
stage('Generate Changelog') {
agent {
label 'linux'
}
steps {
checkout scm
withCredentials([string(credentialsId: 'github-compose-release-test-token', variable: 'GITHUB_TOKEN')]) {
sh "./script/release/generate_changelog.sh"
}
archiveArtifacts artifacts: 'CHANGELOG.md'
stash( name: "changelog", includes: 'CHANGELOG.md' )
}
}
stage('Package') {
parallel {
stage('macosx binary') {
agent {
label 'mac-python'
}
steps {
checkout scm
sh './script/setup/osx'
sh 'tox -e py27,py37 -- tests/unit'
sh './script/build/osx'
dir ('dist') {
checksum('docker-compose-Darwin-x86_64')
checksum('docker-compose-Darwin-x86_64.tgz')
}
archiveArtifacts artifacts: 'dist/*', fingerprint: true
dir("dist") {
stash name: "bin-darwin"
}
}
}
stage('linux binary') {
agent {
label 'linux'
}
steps {
checkout scm
sh ' ./script/build/linux'
dir ('dist') {
checksum('docker-compose-Linux-x86_64')
}
archiveArtifacts artifacts: 'dist/*', fingerprint: true
dir("dist") {
stash name: "bin-linux"
}
}
}
stage('windows binary') {
agent {
label 'windows-python'
}
environment {
PATH = "$PATH;C:\\Python37;C:\\Python37\\Scripts"
}
steps {
checkout scm
bat 'tox.exe -e py27,py37 -- tests/unit'
powershell '.\\script\\build\\windows.ps1'
dir ('dist') {
checksum('docker-compose-Windows-x86_64.exe')
}
archiveArtifacts artifacts: 'dist/*', fingerprint: true
dir("dist") {
stash name: "bin-win"
}
}
}
stage('alpine image') {
agent {
label 'linux'
}
steps {
buildRuntimeImage('alpine')
}
}
stage('debian image') {
agent {
label 'linux'
}
steps {
buildRuntimeImage('debian')
}
}
}
}
stage('Release') {
when {
buildingTag()
}
parallel {
stage('Pushing images') {
agent {
label 'linux'
}
steps {
pushRuntimeImage('alpine')
pushRuntimeImage('debian')
}
}
stage('Creating Github Release') {
agent {
label 'linux'
}
steps {
checkout scm
sh 'mkdir -p dist'
dir("dist") {
unstash "bin-darwin"
unstash "bin-linux"
unstash "bin-win"
unstash "changelog"
githubRelease()
}
}
}
stage('Publishing Python packages') {
agent {
label 'linux'
}
steps {
checkout scm
withCredentials([[$class: "FileBinding", credentialsId: 'pypirc-docker-dsg-cibot', variable: 'PYPIRC']]) {
sh """
virtualenv venv-publish
source venv-publish/bin/activate
python setup.py sdist bdist_wheel
pip install twine
twine upload --config-file ${PYPIRC} ./dist/docker-compose-${env.TAG_NAME}.tar.gz ./dist/docker_compose-${env.TAG_NAME}-py2.py3-none-any.whl
"""
}
}
post {
sh 'deactivate; rm -rf venv-publish'
}
}
}
}
}
}
def buildImage(baseImage) {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
image = docker.image(imageName)
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
try {
image.pull()
} catch (Exception exc) {
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--target build \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT}" \\
.\\
"""
sh "docker push ${imageName}"
}
echo "${imageName}"
return imageName
}
}
}
def runTests(dockerVersion, pythonVersion, baseImage) {
return {
stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
node("linux") {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def storageDriver = sh(script: "docker info -f \'{{.Driver}}\'", returnStdout: true).trim()
echo "Using local system's storage driver: ${storageDriver}"
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
sh """docker run \\
-t \\
--rm \\
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersion}" \\
-e "BUILD_NUMBER=${env.BUILD_NUMBER}" \\
-e "PY_TEST_VERSIONS=${pythonVersion}" \\
--entrypoint="script/test/ci" \\
${imageName} \\
--verbose
"""
}
}
}
}
}
def buildRuntimeImage(baseImage) {
scmvar = checkout scm
def imageName = "docker/compose:${baseImage}-${env.BRANCH_NAME}"
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT.take(7)}" \\
.
"""
}
sh "mkdir -p dist"
sh "docker save ${imageName} -o dist/docker-compose-${baseImage}.tar"
stash name: "compose-${baseImage}", includes: "dist/docker-compose-${baseImage}.tar"
}
def pushRuntimeImage(baseImage) {
unstash "compose-${baseImage}"
sh 'echo -n "${DOCKERHUB_CREDS_PSW}" | docker login --username "${DOCKERHUB_CREDS_USR}" --password-stdin'
sh "docker load -i dist/docker-compose-${baseImage}.tar"
withDockerRegistry(credentialsId: 'dockerbuildbot-hub.docker.com') {
sh "docker push docker/compose:${baseImage}-${env.TAG_NAME}"
if (baseImage == "alpine" && env.TAG_NAME != null) {
sh "docker tag docker/compose:alpine-${env.TAG_NAME} docker/compose:${env.TAG_NAME}"
sh "docker push docker/compose:${env.TAG_NAME}"
}
}
}
def githubRelease() {
withCredentials([string(credentialsId: 'github-compose-release-test-token', variable: 'GITHUB_TOKEN')]) {
def prerelease = !( env.TAG_NAME ==~ /v[0-9\.]+/ )
changelog = readFile "CHANGELOG.md"
def data = """{
\"tag_name\": \"${env.TAG_NAME}\",
\"name\": \"${env.TAG_NAME}\",
\"draft\": true,
\"prerelease\": ${prerelease},
\"body\" : \"${changelog}\"
"""
echo $data
def url = "https://api.github.com/repos/docker/compose/releases"
def upload_url = sh(returnStdout: true, script: """
curl -sSf -H 'Authorization: token ${GITHUB_TOKEN}' -H 'Accept: application/json' -H 'Content-type: application/json' -X POST -d '$data' $url") \\
| jq '.upload_url | .[:rindex("{")]'
""")
sh("""
for f in * ; do
curl -sf -H 'Authorization: token ${GITHUB_TOKEN}' -H 'Accept: application/json' -H 'Content-type: application/octet-stream' \\
-X POST --data-binary @\$f ${upload_url}?name=\$f;
done
""")
}
}
def checksum(filepath) {
if (isUnix()) {
sh "openssl sha256 -r -out ${filepath}.sha256 ${filepath}"
} else {
powershell "(Get-FileHash -Path ${filepath} -Algorithm SHA256 | % hash) + ' *${filepath}' > ${filepath}.sha256"
}
}

View File

@@ -1,24 +0,0 @@
version: '{branch}-{build}'
install:
- "SET PATH=C:\\Python36-x64;C:\\Python36-x64\\Scripts;%PATH%"
- "python --version"
- "pip install tox==2.9.1 virtualenv==15.1.0"
# Build the binary after tests
build: false
test_script:
- "tox -e py27,py36,py37 -- tests/unit"
- ps: ".\\script\\build\\windows.ps1"
artifacts:
- path: .\dist\docker-compose-Windows-x86_64.exe
name: "Compose Windows binary"
deploy:
- provider: Environment
name: master-builds
on:
branch: master

View File

@@ -1,4 +1,4 @@
from __future__ import absolute_import
from __future__ import unicode_literals
__version__ = '1.24.0'
__version__ = '1.25.2-rc1'

View File

@@ -1,258 +0,0 @@
from __future__ import absolute_import
from __future__ import unicode_literals
import json
import logging
import six
from docker.utils import split_command
from docker.utils.ports import split_port
from .cli.errors import UserError
from .config.serialize import denormalize_config
from .network import get_network_defs_for_service
from .service import format_environment
from .service import NoSuchImageError
from .service import parse_repository_tag
log = logging.getLogger(__name__)
SERVICE_KEYS = {
'working_dir': 'WorkingDir',
'user': 'User',
'labels': 'Labels',
}
IGNORED_KEYS = {'build'}
SUPPORTED_KEYS = {
'image',
'ports',
'expose',
'networks',
'command',
'environment',
'entrypoint',
} | set(SERVICE_KEYS)
VERSION = '0.1'
class NeedsPush(Exception):
def __init__(self, image_name):
self.image_name = image_name
class NeedsPull(Exception):
def __init__(self, image_name, service_name):
self.image_name = image_name
self.service_name = service_name
class MissingDigests(Exception):
def __init__(self, needs_push, needs_pull):
self.needs_push = needs_push
self.needs_pull = needs_pull
def serialize_bundle(config, image_digests):
return json.dumps(to_bundle(config, image_digests), indent=2, sort_keys=True)
def get_image_digests(project, allow_push=False):
digests = {}
needs_push = set()
needs_pull = set()
for service in project.services:
try:
digests[service.name] = get_image_digest(
service,
allow_push=allow_push,
)
except NeedsPush as e:
needs_push.add(e.image_name)
except NeedsPull as e:
needs_pull.add(e.service_name)
if needs_push or needs_pull:
raise MissingDigests(needs_push, needs_pull)
return digests
def get_image_digest(service, allow_push=False):
if 'image' not in service.options:
raise UserError(
"Service '{s.name}' doesn't define an image tag. An image name is "
"required to generate a proper image digest for the bundle. Specify "
"an image repo and tag with the 'image' option.".format(s=service))
_, _, separator = parse_repository_tag(service.options['image'])
# Compose file already uses a digest, no lookup required
if separator == '@':
return service.options['image']
try:
image = service.image()
except NoSuchImageError:
action = 'build' if 'build' in service.options else 'pull'
raise UserError(
"Image not found for service '{service}'. "
"You might need to run `docker-compose {action} {service}`."
.format(service=service.name, action=action))
if image['RepoDigests']:
# TODO: pick a digest based on the image tag if there are multiple
# digests
return image['RepoDigests'][0]
if 'build' not in service.options:
raise NeedsPull(service.image_name, service.name)
if not allow_push:
raise NeedsPush(service.image_name)
return push_image(service)
def push_image(service):
try:
digest = service.push()
except Exception:
log.error(
"Failed to push image for service '{s.name}'. Please use an "
"image tag that can be pushed to a Docker "
"registry.".format(s=service))
raise
if not digest:
raise ValueError("Failed to get digest for %s" % service.name)
repo, _, _ = parse_repository_tag(service.options['image'])
identifier = '{repo}@{digest}'.format(repo=repo, digest=digest)
# only do this if RepoDigests isn't already populated
image = service.image()
if not image['RepoDigests']:
# Pull by digest so that image['RepoDigests'] is populated for next time
# and we don't have to pull/push again
service.client.pull(identifier)
log.info("Stored digest for {}".format(service.image_name))
return identifier
def to_bundle(config, image_digests):
if config.networks:
log.warn("Unsupported top level key 'networks' - ignoring")
if config.volumes:
log.warn("Unsupported top level key 'volumes' - ignoring")
config = denormalize_config(config)
return {
'Version': VERSION,
'Services': {
name: convert_service_to_bundle(
name,
service_dict,
image_digests[name],
)
for name, service_dict in config['services'].items()
},
}
def convert_service_to_bundle(name, service_dict, image_digest):
container_config = {'Image': image_digest}
for key, value in service_dict.items():
if key in IGNORED_KEYS:
continue
if key not in SUPPORTED_KEYS:
log.warn("Unsupported key '{}' in services.{} - ignoring".format(key, name))
continue
if key == 'environment':
container_config['Env'] = format_environment({
envkey: envvalue for envkey, envvalue in value.items()
if envvalue
})
continue
if key in SERVICE_KEYS:
container_config[SERVICE_KEYS[key]] = value
continue
set_command_and_args(
container_config,
service_dict.get('entrypoint', []),
service_dict.get('command', []))
container_config['Networks'] = make_service_networks(name, service_dict)
ports = make_port_specs(service_dict)
if ports:
container_config['Ports'] = ports
return container_config
# See https://github.com/docker/swarmkit/blob/agent/exec/container/container.go#L95
def set_command_and_args(config, entrypoint, command):
if isinstance(entrypoint, six.string_types):
entrypoint = split_command(entrypoint)
if isinstance(command, six.string_types):
command = split_command(command)
if entrypoint:
config['Command'] = entrypoint + command
return
if command:
config['Args'] = command
def make_service_networks(name, service_dict):
networks = []
for network_name, network_def in get_network_defs_for_service(service_dict).items():
for key in network_def.keys():
log.warn(
"Unsupported key '{}' in services.{}.networks.{} - ignoring"
.format(key, name, network_name))
networks.append(network_name)
return networks
def make_port_specs(service_dict):
ports = []
internal_ports = [
internal_port
for port_def in service_dict.get('ports', [])
for internal_port in split_port(port_def)[0]
]
internal_ports += service_dict.get('expose', [])
for internal_port in internal_ports:
spec = make_port_spec(internal_port)
if spec not in ports:
ports.append(spec)
return ports
def make_port_spec(value):
components = six.text_type(value).partition('/')
return {
'Protocol': components[2] or 'tcp',
'Port': int(components[0]),
}

View File

@@ -41,9 +41,9 @@ for (name, code) in get_pairs():
def rainbow():
cs = ['cyan', 'yellow', 'green', 'magenta', 'red', 'blue',
cs = ['cyan', 'yellow', 'green', 'magenta', 'blue',
'intense_cyan', 'intense_yellow', 'intense_green',
'intense_magenta', 'intense_red', 'intense_blue']
'intense_magenta', 'intense_blue']
for c in cs:
yield globals()[c]

View File

@@ -13,6 +13,9 @@ from .. import config
from .. import parallel
from ..config.environment import Environment
from ..const import API_VERSIONS
from ..const import LABEL_CONFIG_FILES
from ..const import LABEL_ENVIRONMENT_FILE
from ..const import LABEL_WORKING_DIR
from ..project import Project
from .docker_client import docker_client
from .docker_client import get_tls_version
@@ -21,10 +24,28 @@ from .utils import get_version_info
log = logging.getLogger(__name__)
SILENT_COMMANDS = {
'events',
'exec',
'kill',
'logs',
'pause',
'ps',
'restart',
'rm',
'start',
'stop',
'top',
'unpause',
}
def project_from_options(project_dir, options):
def project_from_options(project_dir, options, additional_options=None):
additional_options = additional_options or {}
override_dir = options.get('--project-directory')
environment = Environment.from_env_file(override_dir or project_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(override_dir or project_dir, environment_file)
environment.silent = options.get('COMMAND', None) in SILENT_COMMANDS
set_parallel_limit(environment)
host = options.get('--host')
@@ -39,7 +60,9 @@ def project_from_options(project_dir, options):
tls_config=tls_config_from_options(options, environment),
environment=environment,
override_dir=override_dir,
compatibility=options.get('--compatibility'),
compatibility=compatibility_from_options(project_dir, options, environment),
interpolate=(not additional_options.get('--no-interpolate')),
environment_file=environment_file
)
@@ -59,15 +82,18 @@ def set_parallel_limit(environment):
parallel.GlobalLimit.set_global_limit(parallel_limit)
def get_config_from_options(base_dir, options):
def get_config_from_options(base_dir, options, additional_options=None):
additional_options = additional_options or {}
override_dir = options.get('--project-directory')
environment = Environment.from_env_file(override_dir or base_dir)
environment_file = options.get('--env-file')
environment = Environment.from_env_file(override_dir or base_dir, environment_file)
config_path = get_config_path_from_options(
base_dir, options, environment
)
return config.load(
config.find(base_dir, config_path, environment, override_dir),
options.get('--compatibility')
compatibility_from_options(config_path, options, environment),
not additional_options.get('--no-interpolate')
)
@@ -105,14 +131,14 @@ def get_client(environment, verbose=False, version=None, tls_config=None, host=N
def get_project(project_dir, config_path=None, project_name=None, verbose=False,
host=None, tls_config=None, environment=None, override_dir=None,
compatibility=False):
compatibility=False, interpolate=True, environment_file=None):
if not environment:
environment = Environment.from_env_file(project_dir)
config_details = config.find(project_dir, config_path, environment, override_dir)
project_name = get_project_name(
config_details.working_dir, project_name, environment
)
config_data = config.load(config_details, compatibility)
config_data = config.load(config_details, compatibility, interpolate)
api_version = environment.get(
'COMPOSE_API_VERSION',
@@ -125,10 +151,40 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False,
with errors.handle_connection_errors(client):
return Project.from_config(
project_name, config_data, client, environment.get('DOCKER_DEFAULT_PLATFORM')
project_name,
config_data,
client,
environment.get('DOCKER_DEFAULT_PLATFORM'),
execution_context_labels(config_details, environment_file),
)
def execution_context_labels(config_details, environment_file):
extra_labels = [
'{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)))
def get_project_name(working_dir, project_name=None, environment=None):
def normalize_name(name):
return re.sub(r'[^-_a-z0-9]', '', name.lower())
@@ -144,3 +200,13 @@ def get_project_name(working_dir, project_name=None, environment=None):
return normalize_name(project)
return 'default'
def compatibility_from_options(working_dir, options=None, environment=None):
"""Get compose v3 compatibility from --compatibility option
or from COMPOSE_COMPATIBILITY environment variable."""
compatibility_option = options.get('--compatibility')
compatibility_environment = environment.get_boolean('COMPOSE_COMPATIBILITY')
return compatibility_option or compatibility_environment

View File

@@ -31,7 +31,7 @@ def get_tls_version(environment):
tls_attr_name = "PROTOCOL_{}".format(compose_tls_version)
if not hasattr(ssl, tls_attr_name):
log.warn(
log.warning(
'The "{}" protocol is unavailable. You may need to update your '
'version of Python or OpenSSL. Falling back to TLSv1 (default).'
.format(compose_tls_version)

View File

@@ -2,25 +2,37 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import logging
import os
import shutil
import six
import texttable
from compose.cli import colors
if hasattr(shutil, "get_terminal_size"):
from shutil import get_terminal_size
else:
from backports.shutil_get_terminal_size import get_terminal_size
def get_tty_width():
tty_size = os.popen('stty size 2> /dev/null', 'r').read().split()
if len(tty_size) != 2:
try:
# get_terminal_size can't determine the size if compose is piped
# to another command. But in such case it doesn't make sense to
# try format the output by terminal size as this output is consumed
# by another command. So let's pretend we have a huge terminal so
# output is single-lined
width, _ = get_terminal_size(fallback=(999, 0))
return int(width)
except OSError:
return 0
_, width = tty_size
return int(width)
class Formatter(object):
class Formatter:
"""Format tabular data for printing."""
def table(self, headers, rows):
@staticmethod
def table(headers, rows):
table = texttable.Texttable(max_width=get_tty_width())
table.set_cols_dtype(['t' for h in headers])
table.add_rows([headers] + rows)

View File

@@ -134,7 +134,10 @@ def build_thread(container, presenter, queue, log_args):
def build_thread_map(initial_containers, presenters, thread_args):
return {
container.id: build_thread(container, next(presenters), *thread_args)
for container in initial_containers
# Container order is unspecified, so they are sorted by name in order to make
# container:presenter (log color) assignment deterministic when given a list of containers
# with the same names.
for container in sorted(initial_containers, key=lambda c: c.name)
}
@@ -230,7 +233,13 @@ def watch_events(thread_map, event_stream, presenters, thread_args):
# Container crashed so we should reattach to it
if event['id'] in crashed_containers:
event['container'].attach_log_stream()
container = event['container']
if not container.is_restarting:
try:
container.attach_log_stream()
except APIError:
# Just ignore errors when reattaching to already crashed containers
pass
crashed_containers.remove(event['id'])
thread_map[event['id']] = build_thread(

View File

@@ -6,6 +6,7 @@ import contextlib
import functools
import json
import logging
import os
import pipes
import re
import subprocess
@@ -14,14 +15,12 @@ from distutils.spawn import find_executable
from inspect import getdoc
from operator import attrgetter
import docker
import docker.errors
import docker.utils
from . import errors
from . import signals
from .. import __version__
from ..bundle import get_image_digests
from ..bundle import MissingDigests
from ..bundle import serialize_bundle
from ..config import ConfigurationError
from ..config import parse_environment
from ..config import parse_labels
@@ -33,6 +32,8 @@ from ..const import COMPOSEFILE_V2_2 as V2_2
from ..const import IS_WINDOWS_PLATFORM
from ..errors import StreamParseError
from ..progress_stream import StreamOutputError
from ..project import get_image_digests
from ..project import MissingDigests
from ..project import NoSuchService
from ..project import OneOffFilter
from ..project import ProjectError
@@ -102,9 +103,9 @@ def dispatch():
options, handler, command_options = dispatcher.parse(sys.argv[1:])
setup_console_handler(console_handler,
options.get('--verbose'),
options.get('--no-ansi'),
set_no_color_if_clicolor(options.get('--no-ansi')),
options.get("--log-level"))
setup_parallel_logger(options.get('--no-ansi'))
setup_parallel_logger(set_no_color_if_clicolor(options.get('--no-ansi')))
if options.get('--no-ansi'):
command_options['--no-color'] = True
return functools.partial(perform_command, options, handler, command_options)
@@ -208,10 +209,10 @@ class TopLevelCommand(object):
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent
--env-file PATH Specify an alternate environment file
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
@@ -246,6 +247,11 @@ class TopLevelCommand(object):
def project_dir(self):
return self.toplevel_options.get('--project-directory') or '.'
@property
def toplevel_environment(self):
environment_file = self.toplevel_options.get('--env-file')
return Environment.from_env_file(self.project_dir, environment_file)
def build(self, options):
"""
Build or rebuild services.
@@ -257,13 +263,18 @@ class TopLevelCommand(object):
Usage: build [options] [--build-arg key=val...] [SERVICE...]
Options:
--build-arg key=val Set build-time variables for services.
--compress Compress the build context using gzip.
--force-rm Always remove intermediate containers.
-m, --memory MEM Set memory limit for the build container.
--no-cache Do not use cache when building the image.
--pull Always attempt to pull a newer version of the image.
-m, --memory MEM Sets memory limit for the build container.
--build-arg key=val Set build-time variables for services.
--no-rm Do not remove intermediate containers after a successful build.
--parallel Build images in parallel.
--progress string Set type of progress output (auto, plain, tty).
EXPERIMENTAL flag for native builder.
To enable, run with COMPOSE_DOCKER_CLI_BUILD=1)
--pull Always attempt to pull a newer version of the image.
-q, --quiet Don't print anything to STDOUT
"""
service_names = options['SERVICE']
build_args = options.get('--build-arg', None)
@@ -273,8 +284,9 @@ class TopLevelCommand(object):
'--build-arg is only supported when services are specified for API version < 1.25.'
' Please use a Compose file version > 2.2 or specify which services to build.'
)
environment = Environment.from_env_file(self.project_dir)
build_args = resolve_build_args(build_args, environment)
build_args = resolve_build_args(build_args, self.toplevel_environment)
native_builder = self.toplevel_environment.get_boolean('COMPOSE_DOCKER_CLI_BUILD')
self.project.build(
service_names=options['SERVICE'],
@@ -282,43 +294,15 @@ class TopLevelCommand(object):
pull=bool(options.get('--pull', False)),
force_rm=bool(options.get('--force-rm', False)),
memory=options.get('--memory'),
rm=not bool(options.get('--no-rm', False)),
build_args=build_args,
gzip=options.get('--compress', False),
parallel_build=options.get('--parallel', False),
silent=options.get('--quiet', False),
cli=native_builder,
progress=options.get('--progress'),
)
def bundle(self, options):
"""
Generate a Distributed Application Bundle (DAB) from the Compose file.
Images must have digests stored, which requires interaction with a
Docker registry. If digests aren't stored for all images, you can fetch
them with `docker-compose pull` or `docker-compose push`. To push images
automatically when bundling, pass `--push-images`. Only services with
a `build` option specified will have their images pushed.
Usage: bundle [options]
Options:
--push-images Automatically push images for any services
which have a `build` option specified.
-o, --output PATH Path to write the bundle file to.
Defaults to "<project name>.dab".
"""
compose_config = get_config_from_options('.', self.toplevel_options)
output = options["--output"]
if not output:
output = "{}.dab".format(self.project.name)
image_digests = image_digests_for_project(self.project, options['--push-images'])
with open(output, 'w') as f:
f.write(serialize_bundle(compose_config, image_digests))
log.info("Wrote bundle to {}".format(output))
def config(self, options):
"""
Validate and view the Compose file.
@@ -327,6 +311,7 @@ class TopLevelCommand(object):
Options:
--resolve-image-digests Pin image tags to digests.
--no-interpolate Don't interpolate environment variables
-q, --quiet Only validate the configuration, don't print
anything.
--services Print the service names, one per line.
@@ -336,11 +321,12 @@ class TopLevelCommand(object):
or use the wildcard symbol to display all services
"""
compose_config = get_config_from_options('.', self.toplevel_options)
additional_options = {'--no-interpolate': options.get('--no-interpolate')}
compose_config = get_config_from_options('.', self.toplevel_options, additional_options)
image_digests = None
if options['--resolve-image-digests']:
self.project = project_from_options('.', self.toplevel_options)
self.project = project_from_options('.', self.toplevel_options, additional_options)
with errors.handle_connection_errors(self.project.client):
image_digests = image_digests_for_project(self.project)
@@ -357,14 +343,14 @@ class TopLevelCommand(object):
if options['--hash'] is not None:
h = options['--hash']
self.project = project_from_options('.', self.toplevel_options)
self.project = project_from_options('.', self.toplevel_options, additional_options)
services = [svc for svc in options['--hash'].split(',')] if h != '*' else None
with errors.handle_connection_errors(self.project.client):
for service in self.project.get_services(services):
print('{} {}'.format(service.name, service.config_hash))
return
print(serialize_config(compose_config, image_digests))
print(serialize_config(compose_config, image_digests, not options['--no-interpolate']))
def create(self, options):
"""
@@ -383,7 +369,7 @@ class TopLevelCommand(object):
"""
service_names = options['SERVICE']
log.warn(
log.warning(
'The create command is deprecated. '
'Use the up command with the --no-start flag instead.'
)
@@ -422,8 +408,7 @@ class TopLevelCommand(object):
-t, --timeout TIMEOUT Specify a shutdown timeout in seconds.
(default: 10)
"""
environment = Environment.from_env_file(self.project_dir)
ignore_orphans = environment.get_boolean('COMPOSE_IGNORE_ORPHANS')
ignore_orphans = self.toplevel_environment.get_boolean('COMPOSE_IGNORE_ORPHANS')
if ignore_orphans and options['--remove-orphans']:
raise UserError("COMPOSE_IGNORE_ORPHANS and --remove-orphans cannot be combined.")
@@ -480,8 +465,7 @@ class TopLevelCommand(object):
not supported in API < 1.25)
-w, --workdir DIR Path to workdir directory for this command.
"""
environment = Environment.from_env_file(self.project_dir)
use_cli = not environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')
use_cli = not self.toplevel_environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')
index = int(options.get('--index'))
service = self.project.get_service(options['SERVICE'])
detach = options.get('--detach')
@@ -504,7 +488,7 @@ class TopLevelCommand(object):
if IS_WINDOWS_PLATFORM or use_cli and not detach:
sys.exit(call_docker(
build_exec_command(options, container.id, command),
self.toplevel_options)
self.toplevel_options, self.toplevel_environment)
)
create_exec_options = {
@@ -604,7 +588,7 @@ class TopLevelCommand(object):
image_id,
size
])
print(Formatter().table(headers, rows))
print(Formatter.table(headers, rows))
def kill(self, options):
"""
@@ -650,7 +634,7 @@ class TopLevelCommand(object):
log_printer_from_project(
self.project,
containers,
options['--no-color'],
set_no_color_if_clicolor(options['--no-color']),
log_args,
event_stream=self.project.events(service_names=options['SERVICE'])).run()
@@ -709,7 +693,8 @@ class TopLevelCommand(object):
if options['--all']:
containers = sorted(self.project.containers(service_names=options['SERVICE'],
one_off=OneOffFilter.include, stopped=True))
one_off=OneOffFilter.include, stopped=True),
key=attrgetter('name'))
else:
containers = sorted(
self.project.containers(service_names=options['SERVICE'], stopped=True) +
@@ -737,7 +722,7 @@ class TopLevelCommand(object):
container.human_readable_state,
container.human_readable_ports,
])
print(Formatter().table(headers, rows))
print(Formatter.table(headers, rows))
def pull(self, options):
"""
@@ -753,7 +738,7 @@ class TopLevelCommand(object):
--include-deps Also pull services declared as dependencies
"""
if options.get('--parallel'):
log.warn('--parallel option is deprecated and will be removed in future versions.')
log.warning('--parallel option is deprecated and will be removed in future versions.')
self.project.pull(
service_names=options['SERVICE'],
ignore_pull_failures=options.get('--ignore-pull-failures'),
@@ -794,7 +779,7 @@ class TopLevelCommand(object):
-a, --all Deprecated - no effect.
"""
if options.get('--all'):
log.warn(
log.warning(
'--all flag is obsolete. This is now the default behavior '
'of `docker-compose rm`'
)
@@ -872,10 +857,12 @@ class TopLevelCommand(object):
else:
command = service.options.get('command')
options['stdin_open'] = service.options.get('stdin_open', True)
container_options = build_one_off_container_options(options, detach, command)
run_one_off_container(
container_options, self.project, service, options,
self.toplevel_options, self.project_dir
self.toplevel_options, self.toplevel_environment
)
def scale(self, options):
@@ -904,7 +891,7 @@ class TopLevelCommand(object):
'Use the up command with the --scale flag instead.'
)
else:
log.warn(
log.warning(
'The scale command is deprecated. '
'Use the up command with the --scale flag instead.'
)
@@ -975,7 +962,7 @@ class TopLevelCommand(object):
rows.append(process)
print(container.name)
print(Formatter().table(headers, rows))
print(Formatter.table(headers, rows))
def unpause(self, options):
"""
@@ -1025,6 +1012,7 @@ class TopLevelCommand(object):
--build Build images before starting containers.
--abort-on-container-exit Stops all containers if any container was
stopped. Incompatible with -d.
--attach-dependencies Attach to dependent containers
-t, --timeout TIMEOUT Use this timeout in seconds for container
shutdown when attached or when containers are
already running. (default: 10)
@@ -1046,20 +1034,23 @@ class TopLevelCommand(object):
remove_orphans = options['--remove-orphans']
detached = options.get('--detach')
no_start = options.get('--no-start')
attach_dependencies = options.get('--attach-dependencies')
if detached and (cascade_stop or exit_value_from):
raise UserError("--abort-on-container-exit and -d cannot be combined.")
if detached and (cascade_stop or exit_value_from or attach_dependencies):
raise UserError(
"-d cannot be combined with --abort-on-container-exit or --attach-dependencies.")
environment = Environment.from_env_file(self.project_dir)
ignore_orphans = environment.get_boolean('COMPOSE_IGNORE_ORPHANS')
ignore_orphans = self.toplevel_environment.get_boolean('COMPOSE_IGNORE_ORPHANS')
if ignore_orphans and remove_orphans:
raise UserError("COMPOSE_IGNORE_ORPHANS and --remove-orphans cannot be combined.")
opts = ['--detach', '--abort-on-container-exit', '--exit-code-from']
opts = ['--detach', '--abort-on-container-exit', '--exit-code-from', '--attach-dependencies']
for excluded in [x for x in opts if options.get(x) and no_start]:
raise UserError('--no-start and {} cannot be combined.'.format(excluded))
native_builder = self.toplevel_environment.get_boolean('COMPOSE_DOCKER_CLI_BUILD')
with up_shutdown_context(self.project, service_names, timeout, detached):
warn_for_swarm_mode(self.project.client)
@@ -1079,6 +1070,7 @@ class TopLevelCommand(object):
reset_container_image=rebuild,
renew_anonymous_volumes=options.get('--renew-anon-volumes'),
silent=options.get('--quiet-pull'),
cli=native_builder,
)
try:
@@ -1098,12 +1090,15 @@ class TopLevelCommand(object):
if detached or no_start:
return
attached_containers = filter_containers_to_service_names(to_attach, service_names)
attached_containers = filter_attached_containers(
to_attach,
service_names,
attach_dependencies)
log_printer = log_printer_from_project(
self.project,
attached_containers,
options['--no-color'],
set_no_color_if_clicolor(options['--no-color']),
{'follow': True},
cascade_stop,
event_stream=self.project.events(service_names=service_names))
@@ -1194,12 +1189,10 @@ def timeout_from_opts(options):
return None if timeout is None else int(timeout)
def image_digests_for_project(project, allow_push=False):
def image_digests_for_project(project):
try:
return get_image_digests(
project,
allow_push=allow_push
)
return get_image_digests(project)
except MissingDigests as e:
def list_images(images):
return "\n".join(" {}".format(name) for name in sorted(images))
@@ -1236,7 +1229,7 @@ def exitval_from_opts(options, project):
exit_value_from = options.get('--exit-code-from')
if exit_value_from:
if not options.get('--abort-on-container-exit'):
log.warn('using --exit-code-from implies --abort-on-container-exit')
log.warning('using --exit-code-from implies --abort-on-container-exit')
options['--abort-on-container-exit'] = True
if exit_value_from not in [s.name for s in project.get_services()]:
log.error('No service named "%s" was found in your compose file.',
@@ -1271,7 +1264,7 @@ def build_one_off_container_options(options, detach, command):
container_options = {
'command': command,
'tty': not (detach or options['-T'] or not sys.stdin.isatty()),
'stdin_open': not detach,
'stdin_open': options.get('stdin_open'),
'detach': detach,
}
@@ -1314,7 +1307,7 @@ def build_one_off_container_options(options, detach, command):
def run_one_off_container(container_options, project, service, options, toplevel_options,
project_dir='.'):
toplevel_environment):
if not options['--no-deps']:
deps = service.get_dependency_names()
if deps:
@@ -1343,8 +1336,7 @@ def run_one_off_container(container_options, project, service, options, toplevel
if options['--rm']:
project.client.remove_container(container.id, force=True, v=True)
environment = Environment.from_env_file(project_dir)
use_cli = not environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')
use_cli = not toplevel_environment.get_boolean('COMPOSE_INTERACTIVE_NO_CLI')
signals.set_signal_handler_to_shutdown()
signals.set_signal_handler_to_hang_up()
@@ -1353,8 +1345,8 @@ def run_one_off_container(container_options, project, service, options, toplevel
if IS_WINDOWS_PLATFORM or use_cli:
service.connect_container_to_networks(container, use_network_aliases)
exit_code = call_docker(
["start", "--attach", "--interactive", container.id],
toplevel_options
get_docker_start_call(container_options, container.id),
toplevel_options, toplevel_environment
)
else:
operation = RunOperation(
@@ -1380,6 +1372,16 @@ def run_one_off_container(container_options, project, service, options, toplevel
sys.exit(exit_code)
def get_docker_start_call(container_options, container_id):
docker_call = ["start"]
if not container_options.get('detach'):
docker_call.append("--attach")
if container_options.get('stdin_open'):
docker_call.append("--interactive")
docker_call.append(container_id)
return docker_call
def log_printer_from_project(
project,
containers,
@@ -1396,8 +1398,8 @@ def log_printer_from_project(
log_args=log_args)
def filter_containers_to_service_names(containers, service_names):
if not service_names:
def filter_attached_containers(containers, service_names, attach_dependencies=False):
if attach_dependencies or not service_names:
return containers
return [
@@ -1434,7 +1436,7 @@ def exit_if(condition, message, exit_code):
raise SystemExit(exit_code)
def call_docker(args, dockeropts):
def call_docker(args, dockeropts, environment):
executable_path = find_executable('docker')
if not executable_path:
raise UserError(errors.docker_not_found_msg("Couldn't find `docker` binary."))
@@ -1464,7 +1466,7 @@ def call_docker(args, dockeropts):
args = [executable_path] + tls_options + args
log.debug(" ".join(map(pipes.quote, args)))
return subprocess.call(args)
return subprocess.call(args, env=environment)
def parse_scale_args(options):
@@ -1565,10 +1567,14 @@ def warn_for_swarm_mode(client):
# UCP does multi-node scheduling with traditional Compose files.
return
log.warn(
log.warning(
"The Docker Engine you're using is running in swarm mode.\n\n"
"Compose does not use swarm mode to deploy services to multiple nodes in a swarm. "
"All containers will be scheduled on the current node.\n\n"
"To deploy your application across the swarm, "
"use `docker stack deploy`.\n"
)
def set_no_color_if_clicolor(no_color_flag):
return no_color_flag or os.environ.get('CLICOLOR') == "0"

View File

@@ -133,12 +133,12 @@ def generate_user_agent():
def human_readable_file_size(size):
suffixes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', ]
order = int(math.log(size, 2) / 10) if size else 0
order = int(math.log(size, 1000)) if size else 0
if order >= len(suffixes):
order = len(suffixes) - 1
return '{0:.3g} {1}'.format(
size / float(1 << (order * 10)),
return '{0:.4g} {1}'.format(
size / pow(10, order * 3),
suffixes[order]
)

View File

@@ -5,6 +5,7 @@ import functools
import io
import logging
import os
import re
import string
import sys
from collections import namedtuple
@@ -198,9 +199,9 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
version = self.config['version']
if isinstance(version, dict):
log.warn('Unexpected type for "version" key in "{}". Assuming '
'"version" is the name of a service, and defaulting to '
'Compose file version 1.'.format(self.filename))
log.warning('Unexpected type for "version" key in "{}". Assuming '
'"version" is the name of a service, and defaulting to '
'Compose file version 1.'.format(self.filename))
return V1
if not isinstance(version, six.string_types):
@@ -214,6 +215,12 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
.format(self.filename, VERSION_EXPLANATION)
)
version_pattern = re.compile(r"^[2-9]+(\.\d+)?$")
if not version_pattern.match(version):
raise ConfigurationError(
'Version "{}" in "{}" is invalid.'
.format(version, self.filename))
if version == '2':
return const.COMPOSEFILE_V2_0
@@ -318,8 +325,8 @@ def get_default_config_files(base_dir):
winner = candidates[0]
if len(candidates) > 1:
log.warn("Found multiple config files with supported names: %s", ", ".join(candidates))
log.warn("Using %s\n", winner)
log.warning("Found multiple config files with supported names: %s", ", ".join(candidates))
log.warning("Using %s\n", winner)
return [os.path.join(path, winner)] + get_default_override_file(path)
@@ -362,7 +369,7 @@ def check_swarm_only_config(service_dicts, compatibility=False):
def check_swarm_only_key(service_dicts, key):
services = [s for s in service_dicts if s.get(key)]
if services:
log.warn(
log.warning(
warning_template.format(
services=", ".join(sorted(s['name'] for s in services)),
key=key
@@ -373,7 +380,7 @@ def check_swarm_only_config(service_dicts, compatibility=False):
check_swarm_only_key(service_dicts, 'configs')
def load(config_details, compatibility=False):
def load(config_details, compatibility=False, interpolate=True):
"""Load the configuration from a working directory and a list of
configuration files. Files are loaded in order, and merged on top
of each other to create the final configuration.
@@ -383,7 +390,7 @@ def load(config_details, compatibility=False):
validate_config_version(config_details.config_files)
processed_files = [
process_config_file(config_file, config_details.environment)
process_config_file(config_file, config_details.environment, interpolate=interpolate)
for config_file in config_details.config_files
]
config_details = config_details._replace(config_files=processed_files)
@@ -505,7 +512,6 @@ def load_services(config_details, config_file, compatibility=False):
def interpolate_config_section(config_file, config, section, environment):
validate_config_section(config_file.filename, config, section)
return interpolate_environment_variables(
config_file.version,
config,
@@ -514,38 +520,60 @@ def interpolate_config_section(config_file, config, section, environment):
)
def process_config_file(config_file, environment, service_name=None):
services = interpolate_config_section(
def process_config_section(config_file, config, section, environment, interpolate):
validate_config_section(config_file.filename, config, section)
if interpolate:
return interpolate_environment_variables(
config_file.version,
config,
section,
environment
)
else:
return config
def process_config_file(config_file, environment, service_name=None, interpolate=True):
services = process_config_section(
config_file,
config_file.get_service_dicts(),
'service',
environment)
environment,
interpolate,
)
if config_file.version > V1:
processed_config = dict(config_file.config)
processed_config['services'] = services
processed_config['volumes'] = interpolate_config_section(
processed_config['volumes'] = process_config_section(
config_file,
config_file.get_volumes(),
'volume',
environment)
processed_config['networks'] = interpolate_config_section(
environment,
interpolate,
)
processed_config['networks'] = process_config_section(
config_file,
config_file.get_networks(),
'network',
environment)
environment,
interpolate,
)
if config_file.version >= const.COMPOSEFILE_V3_1:
processed_config['secrets'] = interpolate_config_section(
processed_config['secrets'] = process_config_section(
config_file,
config_file.get_secrets(),
'secret',
environment)
environment,
interpolate,
)
if config_file.version >= const.COMPOSEFILE_V3_3:
processed_config['configs'] = interpolate_config_section(
processed_config['configs'] = process_config_section(
config_file,
config_file.get_configs(),
'config',
environment
environment,
interpolate,
)
else:
processed_config = services
@@ -594,7 +622,7 @@ class ServiceExtendsResolver(object):
config_path = self.get_extended_config_path(extends)
service_name = extends['service']
if config_path == self.config_file.filename:
if config_path == os.path.abspath(self.config_file.filename):
try:
service_config = self.config_file.get_service(service_name)
except KeyError:
@@ -900,7 +928,7 @@ def finalize_service(service_config, service_names, version, environment, compat
service_dict
)
if ignored_keys:
log.warn(
log.warning(
'The following deploy sub-keys are not supported in compatibility mode and have'
' been ignored: {}'.format(', '.join(ignored_keys))
)

View File

@@ -26,7 +26,7 @@ def split_env(env):
key = env
if re.search(r'\s', key):
raise ConfigurationError(
"environment variable name '{}' may not contains whitespace.".format(key)
"environment variable name '{}' may not contain whitespace.".format(key)
)
return key, value
@@ -56,14 +56,18 @@ class Environment(dict):
def __init__(self, *args, **kwargs):
super(Environment, self).__init__(*args, **kwargs)
self.missing_keys = []
self.silent = False
@classmethod
def from_env_file(cls, base_dir):
def from_env_file(cls, base_dir, env_file=None):
def _initialize():
result = cls()
if base_dir is None:
return result
env_file_path = os.path.join(base_dir, '.env')
if env_file:
env_file_path = os.path.join(base_dir, env_file)
else:
env_file_path = os.path.join(base_dir, '.env')
try:
return cls(env_vars_from_file(env_file_path))
except EnvFileNotFound:
@@ -95,8 +99,8 @@ class Environment(dict):
return super(Environment, self).__getitem__(key.upper())
except KeyError:
pass
if key not in self.missing_keys:
log.warn(
if not self.silent and key not in self.missing_keys:
log.warning(
"The {} variable is not set. Defaulting to a blank string."
.format(key)
)

View File

@@ -64,12 +64,12 @@ def interpolate_value(name, config_key, value, section, interpolator):
string=e.string))
except UnsetRequiredSubstitution as e:
raise ConfigurationError(
'Missing mandatory value for "{config_key}" option in {section} "{name}": {err}'.format(
config_key=config_key,
name=name,
section=section,
err=e.err
)
'Missing mandatory value for "{config_key}" option interpolating {value} '
'in {section} "{name}": {err}'.format(config_key=config_key,
value=value,
name=name,
section=section,
err=e.err)
)

View File

@@ -24,14 +24,12 @@ def serialize_dict_type(dumper, data):
def serialize_string(dumper, data):
""" Ensure boolean-like strings are quoted in the output and escape $ characters """
""" Ensure boolean-like strings are quoted in the output """
representer = dumper.represent_str if six.PY3 else dumper.represent_unicode
if isinstance(data, six.binary_type):
data = data.decode('utf-8')
data = data.replace('$', '$$')
if data.lower() in ('y', 'n', 'yes', 'no', 'on', 'off', 'true', 'false'):
# Empirically only y/n appears to be an issue, but this might change
# depending on which PyYaml version is being used. Err on safe side.
@@ -39,6 +37,12 @@ def serialize_string(dumper, data):
return representer(data)
def serialize_string_escape_dollar(dumper, data):
""" Ensure boolean-like strings are quoted in the output and escape $ characters """
data = data.replace('$', '$$')
return serialize_string(dumper, data)
yaml.SafeDumper.add_representer(types.MountSpec, serialize_dict_type)
yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type)
yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type)
@@ -46,8 +50,6 @@ yaml.SafeDumper.add_representer(types.SecurityOpt, serialize_config_type)
yaml.SafeDumper.add_representer(types.ServiceSecret, serialize_dict_type)
yaml.SafeDumper.add_representer(types.ServiceConfig, serialize_dict_type)
yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type)
yaml.SafeDumper.add_representer(str, serialize_string)
yaml.SafeDumper.add_representer(six.text_type, serialize_string)
def denormalize_config(config, image_digests=None):
@@ -93,7 +95,13 @@ def v3_introduced_name_key(key):
return V3_5
def serialize_config(config, image_digests=None):
def serialize_config(config, image_digests=None, escape_dollar=True):
if escape_dollar:
yaml.SafeDumper.add_representer(str, serialize_string_escape_dollar)
yaml.SafeDumper.add_representer(six.text_type, serialize_string_escape_dollar)
else:
yaml.SafeDumper.add_representer(str, serialize_string)
yaml.SafeDumper.add_representer(six.text_type, serialize_string)
return yaml.safe_dump(
denormalize_config(config, image_digests),
default_flow_style=False,

View File

@@ -11,6 +11,9 @@ IS_WINDOWS_PLATFORM = (sys.platform == "win32")
LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'
LABEL_ONE_OFF = 'com.docker.compose.oneoff'
LABEL_PROJECT = 'com.docker.compose.project'
LABEL_WORKING_DIR = 'com.docker.compose.project.working_dir'
LABEL_CONFIG_FILES = 'com.docker.compose.project.config_files'
LABEL_ENVIRONMENT_FILE = 'com.docker.compose.project.environment_file'
LABEL_SERVICE = 'com.docker.compose.service'
LABEL_NETWORK = 'com.docker.compose.network'
LABEL_VERSION = 'com.docker.compose.version'

View File

@@ -226,12 +226,12 @@ def check_remote_network_config(remote, local):
raise NetworkConfigChangedError(local.true_name, 'enable_ipv6')
local_labels = local.labels or {}
remote_labels = remote.get('Labels', {})
remote_labels = remote.get('Labels') or {}
for k in set.union(set(remote_labels.keys()), set(local_labels.keys())):
if k.startswith('com.docker.'): # We are only interested in user-specified labels
continue
if remote_labels.get(k) != local_labels.get(k):
log.warn(
log.warning(
'Network {}: label "{}" has changed. It may need to be'
' recreated.'.format(local.true_name, k)
)
@@ -276,7 +276,7 @@ class ProjectNetworks(object):
}
unused = set(networks) - set(service_networks) - {'default'}
if unused:
log.warn(
log.warning(
"Some networks were defined but are not used by any service: "
"{}".format(", ".join(unused)))
return cls(service_networks, use_networking)
@@ -288,7 +288,7 @@ class ProjectNetworks(object):
try:
network.remove()
except NotFound:
log.warn("Network %s not found.", network.true_name)
log.warning("Network %s not found.", network.true_name)
def initialize(self):
if not self.use_networking:

View File

@@ -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

View File

@@ -6,13 +6,17 @@ import logging
import operator
import re
from functools import reduce
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
from .cli.errors import UserError
from .config import ConfigurationError
from .config.config import V1
from .config.sort_services import get_container_name_from_network_mode
@@ -24,11 +28,13 @@ 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
from .service import ConvergenceStrategy
from .service import NetworkMode
from .service import NoSuchImageError
from .service import parse_repository_tag
from .service import PidMode
from .service import Service
@@ -38,7 +44,6 @@ from .utils import microseconds_from_time_nano
from .utils import truncate_string
from .volume import ProjectVolumes
log = logging.getLogger(__name__)
@@ -82,10 +87,11 @@ class Project(object):
return labels
@classmethod
def from_config(cls, name, config_data, client, default_platform=None):
def from_config(cls, name, config_data, client, default_platform=None, extra_labels=None):
"""
Construct a Project from a config.Config object.
"""
extra_labels = extra_labels or []
use_networking = (config_data.version and config_data.version != V1)
networks = build_networks(name, config_data, client)
project_networks = ProjectNetworks.from_services(
@@ -135,6 +141,7 @@ class Project(object):
pid_mode=pid_mode,
platform=service_dict.pop('platform', None),
default_platform=default_platform,
extra_labels=extra_labels,
**service_dict)
)
@@ -355,17 +362,27 @@ class Project(object):
return containers
def build(self, service_names=None, no_cache=False, pull=False, force_rm=False, memory=None,
build_args=None, gzip=False, parallel_build=False):
build_args=None, gzip=False, parallel_build=False, rm=True, silent=False, cli=False,
progress=None):
services = []
for service in self.get_services(service_names):
if service.can_be_built():
services.append(service)
else:
elif not silent:
log.info('%s uses an image, skipping' % service.name)
if cli:
log.warning("Native build is an experimental feature and could change at any time")
if parallel_build:
log.warning("Flag '--parallel' is ignored when building with "
"COMPOSE_DOCKER_CLI_BUILD=1")
if gzip:
log.warning("Flag '--compress' is ignored when building with "
"COMPOSE_DOCKER_CLI_BUILD=1")
def build_service(service):
service.build(no_cache, pull, force_rm, memory, build_args, gzip)
service.build(no_cache, pull, force_rm, memory, build_args, gzip, rm, silent, cli, progress)
if parallel_build:
_, errors = parallel.parallel_execute(
@@ -510,8 +527,12 @@ class Project(object):
reset_container_image=False,
renew_anonymous_volumes=False,
silent=False,
cli=False,
):
if cli:
log.warning("Native build is an experimental feature and could change at any time")
self.initialize()
if not ignore_orphans:
self.find_orphan_containers(remove_orphans)
@@ -524,7 +545,7 @@ class Project(object):
include_deps=start_deps)
for svc in services:
svc.ensure_image_exists(do_build=do_build, silent=silent)
svc.ensure_image_exists(do_build=do_build, silent=silent, cli=cli)
plans = self._get_convergence_plans(
services, strategy, always_recreate_deps=always_recreate_deps)
@@ -587,8 +608,10 @@ class Project(object):
", ".join(updated_dependencies))
containers_stopped = any(
service.containers(stopped=True, filters={'status': ['created', 'exited']}))
has_links = any(c.get('HostConfig.Links') for c in service.containers())
if always_recreate_deps or containers_stopped or not has_links:
service_has_links = any(service.get_link_names())
container_has_links = any(c.get('HostConfig.Links') for c in service.containers())
should_recreate_for_links = service_has_links ^ container_has_links
if always_recreate_deps or containers_stopped or should_recreate_for_links:
plan = service.convergence_plan(ConvergenceStrategy.always)
else:
plan = service.convergence_plan(strategy)
@@ -602,46 +625,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)
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,
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:
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()
@@ -686,7 +731,7 @@ class Project(object):
def find_orphan_containers(self, remove_orphans):
def _find():
containers = self._labeled_containers()
containers = set(self._labeled_containers() + self._labeled_containers(stopped=True))
for ctnr in containers:
service_name = ctnr.labels.get(LABEL_SERVICE)
if service_name not in self.service_names:
@@ -697,7 +742,10 @@ class Project(object):
if remove_orphans:
for ctnr in orphans:
log.info('Removing orphan container "{0}"'.format(ctnr.name))
ctnr.kill()
try:
ctnr.kill()
except APIError:
pass
ctnr.remove(force=True)
else:
log.warning(
@@ -725,10 +773,11 @@ class Project(object):
def build_container_operation_with_timeout_func(self, operation, options):
def container_operation_with_timeout(container):
if options.get('timeout') is None:
_options = options.copy()
if _options.get('timeout') is None:
service = self.get_service(container.service)
options['timeout'] = service.stop_timeout(None)
return getattr(container, operation)(**options)
_options['timeout'] = service.stop_timeout(None)
return getattr(container, operation)(**_options)
return container_operation_with_timeout
@@ -771,13 +820,13 @@ def get_secrets(service, service_secrets, secret_defs):
.format(service=service, secret=secret.source))
if secret_def.get('external'):
log.warn("Service \"{service}\" uses secret \"{secret}\" which is external. "
"External secrets are not available to containers created by "
"docker-compose.".format(service=service, secret=secret.source))
log.warning("Service \"{service}\" uses secret \"{secret}\" which is external. "
"External secrets are not available to containers created by "
"docker-compose.".format(service=service, secret=secret.source))
continue
if secret.uid or secret.gid or secret.mode:
log.warn(
log.warning(
"Service \"{service}\" uses secret \"{secret}\" with uid, "
"gid, or mode. These fields are not supported by this "
"implementation of the Compose file".format(
@@ -785,11 +834,104 @@ def get_secrets(service, service_secrets, secret_defs):
)
)
secrets.append({'secret': secret, 'file': secret_def.get('file')})
secret_file = secret_def.get('file')
if not path.isfile(str(secret_file)):
log.warning(
"Service \"{service}\" uses an undefined secret file \"{secret_file}\", "
"the following file should be created \"{secret_file}\"".format(
service=service, secret_file=secret_file
)
)
secrets.append({'secret': secret, 'file': secret_file})
return secrets
def get_image_digests(project):
digests = {}
needs_push = set()
needs_pull = set()
for service in project.services:
try:
digests[service.name] = get_image_digest(service)
except NeedsPush as e:
needs_push.add(e.image_name)
except NeedsPull as e:
needs_pull.add(e.service_name)
if needs_push or needs_pull:
raise MissingDigests(needs_push, needs_pull)
return digests
def get_image_digest(service):
if 'image' not in service.options:
raise UserError(
"Service '{s.name}' doesn't define an image tag. An image name is "
"required to generate a proper image digest. Specify an image repo "
"and tag with the 'image' option.".format(s=service))
_, _, separator = parse_repository_tag(service.options['image'])
# Compose file already uses a digest, no lookup required
if separator == '@':
return service.options['image']
digest = get_digest(service)
if digest:
return digest
if 'build' not in service.options:
raise NeedsPull(service.image_name, service.name)
raise NeedsPush(service.image_name)
def get_digest(service):
digest = None
try:
image = service.image()
# TODO: pick a digest based on the image tag if there are multiple
# digests
if image['RepoDigests']:
digest = image['RepoDigests'][0]
except NoSuchImageError:
try:
# Fetch the image digest from the registry
distribution = service.get_image_registry_data()
if distribution['Descriptor']['digest']:
digest = '{image_name}@{digest}'.format(
image_name=service.image_name,
digest=distribution['Descriptor']['digest']
)
except NoSuchImageError:
raise UserError(
"Digest not found for service '{service}'. "
"Repository does not exist or may require 'docker login'"
.format(service=service.name))
return digest
class MissingDigests(Exception):
def __init__(self, needs_push, needs_pull):
self.needs_push = needs_push
self.needs_pull = needs_pull
class NeedsPush(Exception):
def __init__(self, image_name):
self.image_name = image_name
class NeedsPull(Exception):
def __init__(self, image_name, service_name):
self.image_name = image_name
self.service_name = service_name
class NoSuchService(Exception):
def __init__(self, name):
if isinstance(name, six.binary_type):

View File

@@ -2,10 +2,12 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import itertools
import json
import logging
import os
import re
import sys
import tempfile
from collections import namedtuple
from collections import OrderedDict
from operator import attrgetter
@@ -58,11 +60,15 @@ 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
else:
import subprocess
log = logging.getLogger(__name__)
HOST_CONFIG_KEYS = [
'cap_add',
'cap_drop',
@@ -131,7 +137,6 @@ class NoSuchImageError(Exception):
ServiceName = namedtuple('ServiceName', 'project service number')
ConvergencePlan = namedtuple('ConvergencePlan', 'action containers')
@@ -167,20 +172,21 @@ class BuildAction(enum.Enum):
class Service(object):
def __init__(
self,
name,
client=None,
project='default',
use_networking=False,
links=None,
volumes_from=None,
network_mode=None,
networks=None,
secrets=None,
scale=None,
pid_mode=None,
default_platform=None,
**options
self,
name,
client=None,
project='default',
use_networking=False,
links=None,
volumes_from=None,
network_mode=None,
networks=None,
secrets=None,
scale=1,
pid_mode=None,
default_platform=None,
extra_labels=None,
**options
):
self.name = name
self.client = client
@@ -192,9 +198,10 @@ class Service(object):
self.pid_mode = pid_mode or PidMode(None)
self.networks = networks or {}
self.secrets = secrets or []
self.scale_num = scale or 1
self.scale_num = scale
self.default_platform = default_platform
self.options = options
self.extra_labels = extra_labels or []
def __repr__(self):
return '<Service: {}>'.format(self.name)
@@ -209,7 +216,7 @@ class Service(object):
for container in self.client.containers(
all=stopped,
filters=filters)])
)
)
if result:
return result
@@ -241,15 +248,15 @@ class Service(object):
def show_scale_warnings(self, desired_num):
if self.custom_container_name and desired_num > 1:
log.warn('The "%s" service is using the custom container name "%s". '
'Docker requires each container to have a unique name. '
'Remove the custom name to scale the service.'
% (self.name, self.custom_container_name))
log.warning('The "%s" service is using the custom container name "%s". '
'Docker requires each container to have a unique name. '
'Remove the custom name to scale the service.'
% (self.name, self.custom_container_name))
if self.specifies_host_port() and desired_num > 1:
log.warn('The "%s" service specifies a port on the host. If multiple containers '
'for this service are created on a single host, the port will clash.'
% self.name)
log.warning('The "%s" service specifies a port on the host. If multiple containers '
'for this service are created on a single host, the port will clash.'
% self.name)
def scale(self, desired_num, timeout=None):
"""
@@ -337,11 +344,11 @@ 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):
def ensure_image_exists(self, do_build=BuildAction.none, silent=False, cli=False):
if self.can_be_built() and do_build == BuildAction.force:
self.build()
self.build(cli=cli)
return
try:
@@ -357,12 +364,18 @@ class Service(object):
if do_build == BuildAction.skip:
raise NeedsBuildError(self)
self.build()
log.warn(
self.build(cli=cli)
log.warning(
"Image for service {} was built because it did not already exist. To "
"rebuild this image you must use `docker-compose build` or "
"`docker-compose up --build`.".format(self.name))
def get_image_registry_data(self):
try:
return self.client.inspect_distribution(self.image_name)
except APIError:
raise NoSuchImageError("Image '{}' not found".format(self.image_name))
def image(self):
try:
return self.client.inspect_image(self.image_name)
@@ -392,8 +405,8 @@ class Service(object):
return ConvergencePlan('start', containers)
if (
strategy is ConvergenceStrategy.always or
self._containers_have_diverged(containers)
strategy is ConvergenceStrategy.always or
self._containers_have_diverged(containers)
):
return ConvergencePlan('recreate', containers)
@@ -470,6 +483,7 @@ class Service(object):
container, timeout=timeout, attach_logs=not detached,
start_new_container=start, renew_anonymous_volumes=renew_anonymous_volumes
)
containers, errors = parallel_execute(
containers,
recreate,
@@ -611,7 +625,10 @@ class Service(object):
try:
container.start()
except APIError as ex:
raise OperationFailedError("Cannot start service %s: %s" % (self.name, 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, expl))
return container
@property
@@ -680,6 +697,7 @@ class Service(object):
'links': self.get_link_names(),
'net': self.network_mode.id,
'networks': self.networks,
'secrets': self.secrets,
'volumes_from': [
(v.source.name, v.mode)
for v in self.volumes_from if isinstance(v.source, Service)
@@ -690,11 +708,11 @@ class Service(object):
net_name = self.network_mode.service_name
pid_namespace = self.pid_mode.service_name
return (
self.get_linked_service_names() +
self.get_volumes_from_names() +
([net_name] if net_name else []) +
([pid_namespace] if pid_namespace else []) +
list(self.options.get('depends_on', {}).keys())
self.get_linked_service_names() +
self.get_volumes_from_names() +
([net_name] if net_name else []) +
([pid_namespace] if pid_namespace else []) +
list(self.options.get('depends_on', {}).keys())
)
def get_dependency_configs(self):
@@ -884,7 +902,7 @@ class Service(object):
container_options['labels'] = build_container_labels(
container_options.get('labels', {}),
self.labels(one_off=one_off),
self.labels(one_off=one_off) + self.extra_labels,
number,
self.config_hash if add_config_hash else None,
slug
@@ -1043,8 +1061,11 @@ class Service(object):
return [build_spec(secret) for secret in self.secrets]
def build(self, no_cache=False, pull=False, force_rm=False, memory=None, build_args_override=None,
gzip=False):
log.info('Building %s' % self.name)
gzip=False, rm=True, silent=False, cli=False, progress=None):
output_stream = open(os.devnull, 'w')
if not silent:
output_stream = sys.stdout
log.info('Building %s' % self.name)
build_opts = self.options.get('build', {})
@@ -1061,15 +1082,16 @@ class Service(object):
'Impossible to perform platform-targeted builds for API version < 1.35'
)
build_output = self.client.build(
builder = self.client if not cli else _CLIBuilder(progress)
build_output = builder.build(
path=path,
tag=self.image_name,
rm=True,
rm=rm,
forcerm=force_rm,
pull=pull,
nocache=no_cache,
dockerfile=build_opts.get('dockerfile', None),
cache_from=build_opts.get('cache_from', None),
cache_from=self.get_cache_from(build_opts),
labels=build_opts.get('labels', None),
buildargs=build_args,
network_mode=build_opts.get('network', None),
@@ -1085,7 +1107,7 @@ class Service(object):
)
try:
all_events = list(stream_output(build_output, sys.stdout))
all_events = list(stream_output(build_output, output_stream))
except StreamOutputError as e:
raise BuildError(self, six.text_type(e))
@@ -1107,6 +1129,12 @@ class Service(object):
return image_id
def get_cache_from(self, build_opts):
cache_from = build_opts.get('cache_from', None)
if cache_from is not None:
cache_from = [tag for tag in cache_from if tag]
return cache_from
def can_be_built(self):
return 'build' in self.options
@@ -1316,7 +1344,7 @@ class ServicePidMode(PidMode):
if containers:
return 'container:' + containers[0].id
log.warn(
log.warning(
"Service %s is trying to use reuse the PID namespace "
"of another service that is not running." % (self.service_name)
)
@@ -1379,8 +1407,8 @@ class ServiceNetworkMode(object):
if containers:
return 'container:' + containers[0].id
log.warn("Service %s is trying to use reuse the network stack "
"of another service that is not running." % (self.id))
log.warning("Service %s is trying to use reuse the network stack "
"of another service that is not running." % (self.id))
return None
@@ -1527,11 +1555,11 @@ def warn_on_masked_volume(volumes_option, container_volumes, service):
for volume in volumes_option:
if (
volume.external and
volume.internal in container_volumes and
container_volumes.get(volume.internal) != volume.external
volume.external and
volume.internal in container_volumes and
container_volumes.get(volume.internal) != volume.external
):
log.warn((
log.warning((
"Service \"{service}\" is using volume \"{volume}\" from the "
"previous container. Host mapping \"{host_path}\" has no effect. "
"Remove the existing containers (with `docker-compose rm {service}`) "
@@ -1576,6 +1604,7 @@ def build_mount(mount_spec):
read_only=mount_spec.read_only, consistency=mount_spec.consistency, **kwargs
)
# Labels
@@ -1630,6 +1659,7 @@ def format_environment(environment):
if isinstance(value, six.binary_type):
value = value.decode('utf-8')
return '{key}={value}'.format(key=key, value=value)
return [format_env(*item) for item in environment.items()]
@@ -1686,3 +1716,139 @@ def rewrite_build_path(path):
path = WINDOWS_LONGPATH_PREFIX + os.path.normpath(path)
return path
class _CLIBuilder(object):
def __init__(self, progress):
self._progress = progress
def build(self, path, tag=None, quiet=False, fileobj=None,
nocache=False, rm=False, timeout=None,
custom_context=False, encoding=None, pull=False,
forcerm=False, dockerfile=None, container_limits=None,
decode=False, buildargs=None, gzip=False, shmsize=None,
labels=None, cache_from=None, target=None, network_mode=None,
squash=None, extra_hosts=None, platform=None, isolation=None,
use_config_proxy=True):
"""
Args:
path (str): Path to the directory containing the Dockerfile
buildargs (dict): A dictionary of build arguments
cache_from (:py:class:`list`): A list of images used for build
cache resolution
container_limits (dict): A dictionary of limits applied to each
container created by the build process. Valid keys:
- memory (int): set memory limit for build
- memswap (int): Total memory (memory + swap), -1 to disable
swap
- cpushares (int): CPU shares (relative weight)
- cpusetcpus (str): CPUs in which to allow execution, e.g.,
``"0-3"``, ``"0,1"``
custom_context (bool): Optional if using ``fileobj``
decode (bool): If set to ``True``, the returned stream will be
decoded into dicts on the fly. Default ``False``
dockerfile (str): path within the build context to the Dockerfile
encoding (str): The encoding for a stream. Set to ``gzip`` for
compressing
extra_hosts (dict): Extra hosts to add to /etc/hosts in building
containers, as a mapping of hostname to IP address.
fileobj: A file object to use as the Dockerfile. (Or a file-like
object)
forcerm (bool): Always remove intermediate containers, even after
unsuccessful builds
isolation (str): Isolation technology used during build.
Default: `None`.
labels (dict): A dictionary of labels to set on the image
network_mode (str): networking mode for the run commands during
build
nocache (bool): Don't use the cache when set to ``True``
platform (str): Platform in the format ``os[/arch[/variant]]``
pull (bool): Downloads any updates to the FROM image in Dockerfiles
quiet (bool): Whether to return the status
rm (bool): Remove intermediate containers. The ``docker build``
command now defaults to ``--rm=true``, but we have kept the old
default of `False` to preserve backward compatibility
shmsize (int): Size of `/dev/shm` in bytes. The size must be
greater than 0. If omitted the system uses 64MB
squash (bool): Squash the resulting images layers into a
single layer.
tag (str): A tag to add to the final image
target (str): Name of the build-stage to build in a multi-stage
Dockerfile
timeout (int): HTTP timeout
use_config_proxy (bool): If ``True``, and if the docker client
configuration file (``~/.docker/config.json`` by default)
contains a proxy configuration, the corresponding environment
variables will be set in the container being built.
Returns:
A generator for the build output.
"""
if dockerfile:
dockerfile = os.path.join(path, dockerfile)
iidfile = tempfile.mktemp()
command_builder = _CommandBuilder()
command_builder.add_params("--build-arg", buildargs)
command_builder.add_list("--cache-from", cache_from)
command_builder.add_arg("--file", dockerfile)
command_builder.add_flag("--force-rm", forcerm)
command_builder.add_arg("--memory", container_limits.get("memory"))
command_builder.add_flag("--no-cache", nocache)
command_builder.add_arg("--progress", self._progress)
command_builder.add_flag("--pull", pull)
command_builder.add_arg("--tag", tag)
command_builder.add_arg("--target", target)
command_builder.add_arg("--iidfile", iidfile)
args = command_builder.build([path])
magic_word = "Successfully built "
appear = False
with subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True) as p:
while True:
line = p.stdout.readline()
if not line:
break
# Fix non ascii chars on Python2. To remove when #6890 is complete.
if six.PY2:
magic_word = str(magic_word)
if line.startswith(magic_word):
appear = True
yield json.dumps({"stream": line})
with open(iidfile) as f:
line = f.readline()
image_id = line.split(":")[1].strip()
os.remove(iidfile)
# In case of `DOCKER_BUILDKIT=1`
# there is no success message already present in the output.
# Since that's the way `Service::build` gets the `image_id`
# it has to be added `manually`
if not appear:
yield json.dumps({"stream": "{}{}\n".format(magic_word, image_id)})
class _CommandBuilder(object):
def __init__(self):
self._args = ["docker", "build"]
def add_arg(self, name, value):
if value:
self._args.extend([name, str(value)])
def add_flag(self, name, flag):
if flag:
self._args.extend([name])
def add_params(self, name, params):
if params:
for key, val in params.items():
self._args.extend([name, "{}={}".format(key, val)])
def add_list(self, name, values):
if values:
for val in values:
self._args.extend([name, val])
def build(self, args):
return self._args + args

View File

@@ -127,7 +127,7 @@ class ProjectVolumes(object):
try:
volume.remove()
except NotFound:
log.warn("Volume %s not found.", volume.true_name)
log.warning("Volume %s not found.", volume.true_name)
def initialize(self):
try:
@@ -209,7 +209,7 @@ def check_remote_volume_config(remote, local):
if k.startswith('com.docker.'): # We are only interested in user-specified labels
continue
if remote_labels.get(k) != local_labels.get(k):
log.warn(
log.warning(
'Volume {}: label "{}" has changed. It may need to be'
' recreated.'.format(local.name, k)
)

View File

@@ -110,11 +110,14 @@ _docker_compose_build() {
__docker_compose_nospace
return
;;
--memory|-m)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--build-arg --compress --force-rm --help --memory --no-cache --pull --parallel" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--build-arg --compress --force-rm --help --memory -m --no-cache --no-rm --pull --parallel -q --quiet" -- "$cur" ) )
;;
*)
__docker_compose_complete_services --filter source=build
@@ -123,18 +126,6 @@ _docker_compose_build() {
}
_docker_compose_bundle() {
case "$prev" in
--output|-o)
_filedir
return
;;
esac
COMPREPLY=( $( compgen -W "--push-images --help --output -o" -- "$cur" ) )
}
_docker_compose_config() {
case "$prev" in
--hash)
@@ -147,7 +138,7 @@ _docker_compose_config() {
;;
esac
COMPREPLY=( $( compgen -W "--hash --help --quiet -q --resolve-image-digests --services --volumes" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--hash --help --no-interpolate --quiet -q --resolve-image-digests --services --volumes" -- "$cur" ) )
}
@@ -181,6 +172,10 @@ _docker_compose_docker_compose() {
_filedir -d
return
;;
--env-file)
_filedir
return
;;
$(__docker_compose_to_extglob "$daemon_options_with_args") )
return
;;
@@ -550,7 +545,7 @@ _docker_compose_up() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--abort-on-container-exit --always-recreate-deps --build -d --detach --exit-code-from --force-recreate --help --no-build --no-color --no-deps --no-recreate --no-start --renew-anon-volumes -V --remove-orphans --scale --timeout -t" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--abort-on-container-exit --always-recreate-deps --attach-dependencies --build -d --detach --exit-code-from --force-recreate --help --no-build --no-color --no-deps --no-recreate --no-start --renew-anon-volumes -V --remove-orphans --scale --timeout -t" -- "$cur" ) )
;;
*)
__docker_compose_complete_services
@@ -574,7 +569,6 @@ _docker_compose() {
local commands=(
build
bundle
config
create
down
@@ -609,6 +603,7 @@ _docker_compose() {
--tlsverify
"
local daemon_options_with_args="
--env-file
--file -f
--host -H
--project-directory

View File

@@ -12,6 +12,7 @@ end
complete -c docker-compose -s f -l file -r -d 'Specify an alternate compose file'
complete -c docker-compose -s p -l project-name -x -d 'Specify an alternate project name'
complete -c docker-compose -l env-file -r -d 'Specify an alternate environment file (default: .env)'
complete -c docker-compose -l verbose -d 'Show more output'
complete -c docker-compose -s H -l host -x -d 'Daemon socket to connect to'
complete -c docker-compose -l tls -d 'Use TLS; implied by --tlsverify'

View File

@@ -113,6 +113,7 @@ __docker-compose_subcommand() {
$opts_help \
"*--build-arg=[Set build-time variables for one service.]:<varname>=<value>: " \
'--force-rm[Always remove intermediate containers.]' \
'(--quiet -q)'{--quiet,-q}'[Curb build output]' \
'(--memory -m)'{--memory,-m}'[Memory limit for the build container.]' \
'--no-cache[Do not use cache when building the image.]' \
'--pull[Always attempt to pull a newer version of the image.]' \
@@ -120,12 +121,6 @@ __docker-compose_subcommand() {
'--parallel[Build images in parallel.]' \
'*:services:__docker-compose_services_from_build' && ret=0
;;
(bundle)
_arguments \
$opts_help \
'--push-images[Automatically push images for any services which have a `build` option specified.]' \
'(--output -o)'{--output,-o}'[Path to write the bundle file to. Defaults to "<project name>.dab".]:file:_files' && ret=0
;;
(config)
_arguments \
$opts_help \
@@ -289,7 +284,7 @@ __docker-compose_subcommand() {
(up)
_arguments \
$opts_help \
'(--abort-on-container-exit)-d[Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit.]' \
'(--abort-on-container-exit)-d[Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit and --attach-dependencies.]' \
$opts_no_color \
$opts_no_deps \
$opts_force_recreate \
@@ -297,6 +292,7 @@ __docker-compose_subcommand() {
$opts_no_build \
"(--no-build)--build[Build images before starting containers.]" \
"(-d)--abort-on-container-exit[Stops all containers if any container was stopped. Incompatible with -d.]" \
"(-d)--attach-dependencies[Attach to dependent containers. Incompatible with -d.]" \
'(-t --timeout)'{-t,--timeout}"[Use this timeout in seconds for container shutdown when attached or when containers are already running. (default: 10)]:seconds: " \
'--scale[SERVICE=NUM Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.]:service scale SERVICE=NUM: ' \
'--exit-code-from=[Return the exit code of the selected service container. Implies --abort-on-container-exit]:service:__docker-compose_services' \
@@ -340,6 +336,7 @@ _docker-compose() {
'(- :)'{-h,--help}'[Get help]' \
'*'{-f,--file}"[${file_description}]:file:_files -g '*.yml'" \
'(-p --project-name)'{-p,--project-name}'[Specify an alternate project name (default: directory name)]:project name:' \
'--env-file[Specify an alternate environment file (default: .env)]:env-file:_files' \
"--compatibility[If set, Compose will attempt to convert keys in v3 files to their non-Swarm equivalent]" \
'(- :)'{-v,--version}'[Print version and exit]' \
'--verbose[Show more output]' \
@@ -358,6 +355,7 @@ _docker-compose() {
local -a relevant_compose_flags relevant_compose_repeatable_flags relevant_docker_flags compose_options docker_options
relevant_compose_flags=(
"--env-file"
"--file" "-f"
"--host" "-H"
"--project-name" "-p"

View File

@@ -44,7 +44,7 @@ def warn_for_links(name, service):
links = service.get('links')
if links:
example_service = links[0].partition(':')[0]
log.warn(
log.warning(
"Service {name} has links, which no longer create environment "
"variables such as {example_service_upper}_PORT. "
"If you are using those in your application code, you should "
@@ -57,7 +57,7 @@ def warn_for_links(name, service):
def warn_for_external_links(name, service):
external_links = service.get('external_links')
if external_links:
log.warn(
log.warning(
"Service {name} has external_links: {ext}, which now work "
"slightly differently. In particular, two containers must be "
"connected to at least one network in common in order to "
@@ -107,7 +107,7 @@ def rewrite_volumes_from(service, service_names):
def create_volumes_section(data):
named_volumes = get_named_volumes(data['services'])
if named_volumes:
log.warn(
log.warning(
"Named volumes ({names}) must be explicitly declared. Creating a "
"'volumes' section with declarations.\n\n"
"For backwards-compatibility, they've been declared as external. "

20
docker-compose-entrypoint.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
set -e
# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
set -- docker-compose "$@"
fi
# if our command is a valid Docker subcommand, let's invoke it through Docker instead
# (this allows for "docker run docker ps", etc)
if docker-compose help "$1" > /dev/null 2>&1; then
set -- docker-compose "$@"
fi
# if we have "--link some-docker:docker" and not DOCKER_HOST, let's set DOCKER_HOST automatically
if [ -z "$DOCKER_HOST" -a "$DOCKER_PORT_2375_TCP" ]; then
export DOCKER_HOST='tcp://docker:2375'
fi
exec "$@"

108
docker-compose_darwin.spec Normal file
View 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')

View File

@@ -6,11 +6,9 @@ The documentation for Compose has been merged into
The docs for Compose are now here:
https://github.com/docker/docker.github.io/tree/master/compose
Please submit pull requests for unpublished features on the `vnext-compose` branch (https://github.com/docker/docker.github.io/tree/vnext-compose).
Please submit pull requests for unreleased features/changes on the `master` branch (https://github.com/docker/docker.github.io/tree/master), please prefix the PR title with `[WIP]` to indicate that it relates to an unreleased change.
If you submit a PR to this codebase that has a docs impact, create a second docs PR on `docker.github.io`. Use the docs PR template provided (coming soon - watch this space).
PRs for typos, additional information, etc. for already-published features should be labeled as `okay-to-publish` (we are still settling on a naming convention, will provide a label soon). You can submit these PRs either to `vnext-compose` or directly to `master` on `docker.github.io`
If you submit a PR to this codebase that has a docs impact, create a second docs PR on `docker.github.io`. Use the docs PR template provided.
As always, the docs remain open-source and we appreciate your feedback and
pull requests!

13
pyinstaller/ldd Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
# From http://wiki.musl-libc.org/wiki/FAQ#Q:_where_is_ldd_.3F
#
# Musl's dynlinker comes with ldd functionality built in. just create a
# symlink from ld-musl-$ARCH.so to /bin/ldd. If the dynlinker was started
# as "ldd", it will detect that and print the appropriate DSO information.
#
# Instead, this string replaced "ldd" with the package so that pyinstaller
# can find the actual lib.
exec /usr/bin/ldd "$@" | \
sed -r 's/([^[:space:]]+) => ldd/\1 => \/lib\/\1/g' | \
sed -r 's/ldd \(.*\)//g'

View File

@@ -1 +1 @@
pyinstaller==3.3.1
pyinstaller==3.6

View File

@@ -1,5 +1,7 @@
coverage==4.4.2
flake8==3.5.0
mock==2.0.0
pytest==3.6.3
pytest-cov==2.5.1
coverage==5.0.3
ddt==1.2.2
flake8==3.7.9
mock==3.0.5
pytest==5.3.2; python_version >= '3.5'
pytest==4.6.5; python_version < '3.5'
pytest-cov==2.8.1

View File

@@ -1,24 +1,26 @@
backports.shutil_get_terminal_size==1.0.0
backports.ssl-match-hostname==3.5.0.1; python_version < '3'
cached-property==1.3.0
certifi==2017.4.17
cached-property==1.5.1
certifi==2019.11.28
chardet==3.0.4
colorama==0.4.0; sys_platform == 'win32'
docker==3.7.2
colorama==0.4.3; sys_platform == 'win32'
docker==4.1.0
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
enum34==1.1.6; python_version < '3.4'
functools32==3.2.3.post2; python_version < '3.2'
idna==2.5
ipaddress==1.0.18
jsonschema==2.6.0
paramiko==2.4.2
idna==2.8
ipaddress==1.0.23
jsonschema==3.2.0
paramiko==2.7.1
pypiwin32==219; sys_platform == 'win32' and python_version < '3.6'
pypiwin32==223; sys_platform == 'win32' and python_version >= '3.6'
PySocks==1.6.7
PyYAML==4.2b1
requests==2.20.0
six==1.10.0
texttable==0.9.1
urllib3==1.21.1; python_version == '3.3'
websocket-client==0.32.0
PySocks==1.7.1
PyYAML==5.3
requests==2.22.0
six==1.12.0
subprocess32==3.5.4; python_version < '3.2'
texttable==1.6.2
urllib3==1.25.7; python_version == '3.3'
websocket-client==0.57.0

View File

@@ -7,11 +7,14 @@ if [ -z "$1" ]; then
exit 1
fi
TAG=$1
TAG="$1"
VERSION="$(python setup.py --version)"
./script/build/write-git-sha
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
echo "${DOCKER_COMPOSE_GITSHA}" > compose/GITSHA
python setup.py sdist bdist_wheel
./script/build/linux
docker build -t docker/compose:$TAG -f Dockerfile.run .
docker build \
--build-arg GIT_COMMIT="${DOCKER_COMPOSE_GITSHA}" \
-t "${TAG}" .

View File

@@ -4,10 +4,15 @@ set -ex
./script/clean
TAG="docker-compose"
docker build -t "$TAG" .
docker run \
--rm --entrypoint="script/build/linux-entrypoint" \
-v $(pwd)/dist:/code/dist \
-v $(pwd)/.git:/code/.git \
"$TAG"
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
TAG="docker/compose:tmp-glibc-linux-binary-${DOCKER_COMPOSE_GITSHA}"
docker build -t "${TAG}" . \
--build-arg BUILD_PLATFORM=debian \
--build-arg GIT_COMMIT="${DOCKER_COMPOSE_GITSHA}"
TMP_CONTAINER=$(docker create "${TAG}")
mkdir -p dist
ARCH=$(uname -m)
docker cp "${TMP_CONTAINER}":/usr/local/bin/docker-compose "dist/docker-compose-Linux-${ARCH}"
docker container rm -f "${TMP_CONTAINER}"
docker image rm -f "${TAG}"

View File

@@ -2,14 +2,39 @@
set -ex
TARGET=dist/docker-compose-$(uname -s)-$(uname -m)
VENV=/code/.tox/py36
CODE_PATH=/code
VENV="${CODE_PATH}"/.tox/py37
mkdir -p `pwd`/dist
chmod 777 `pwd`/dist
cd "${CODE_PATH}"
mkdir -p dist
chmod 777 dist
$VENV/bin/pip install -q -r requirements-build.txt
./script/build/write-git-sha
su -c "$VENV/bin/pyinstaller docker-compose.spec" user
mv dist/docker-compose $TARGET
$TARGET version
"${VENV}"/bin/pip3 install -q -r requirements-build.txt
# TODO(ulyssessouza) To check if really needed
if [ -z "${DOCKER_COMPOSE_GITSHA}" ]; then
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
fi
echo "${DOCKER_COMPOSE_GITSHA}" > compose/GITSHA
export PATH="${CODE_PATH}/pyinstaller:${PATH}"
if [ ! -z "${BUILD_BOOTLOADER}" ]; then
# Build bootloader for alpine; develop is the main branch
git clone --single-branch --branch develop https://github.com/pyinstaller/pyinstaller.git /tmp/pyinstaller
cd /tmp/pyinstaller/bootloader
# Checkout commit corresponding to version in requirements-build
git checkout v3.6
"${VENV}"/bin/python3 ./waf configure --no-lsb all
"${VENV}"/bin/pip3 install ..
cd "${CODE_PATH}"
rm -Rf /tmp/pyinstaller
else
echo "NOT compiling bootloader!!!"
fi
"${VENV}"/bin/pyinstaller --exclude-module pycrypto --exclude-module PyInstaller docker-compose.spec
ls -la dist/
ldd dist/docker-compose
mv dist/docker-compose /usr/local/bin
docker-compose version

View File

@@ -5,11 +5,20 @@ TOOLCHAIN_PATH="$(realpath $(dirname $0)/../../build/toolchain)"
rm -rf venv
virtualenv -p ${TOOLCHAIN_PATH}/bin/python3 venv
virtualenv -p "${TOOLCHAIN_PATH}"/bin/python3 venv
venv/bin/pip install -r requirements.txt
venv/bin/pip install -r requirements-build.txt
venv/bin/pip install --no-deps .
./script/build/write-git-sha
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

View File

@@ -7,11 +7,12 @@ if [ -z "$1" ]; then
exit 1
fi
TAG=$1
TAG="$1"
IMAGE="docker/compose-tests"
docker build -t docker-compose-tests:tmp .
ctnr_id=$(docker create --entrypoint=tox docker-compose-tests:tmp)
docker commit $ctnr_id docker/compose-tests:latest
docker tag docker/compose-tests:latest docker/compose-tests:$TAG
docker rm -f $ctnr_id
docker rmi -f docker-compose-tests:tmp
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
docker build -t "${IMAGE}:${TAG}" . \
--target build \
--build-arg BUILD_PLATFORM="debian" \
--build-arg GIT_COMMIT="${DOCKER_COMPOSE_GITSHA}"
docker tag "${IMAGE}":"${TAG}" "${IMAGE}":latest

View File

@@ -6,17 +6,17 @@
#
# http://git-scm.com/download/win
#
# 2. Install Python 3.6.4:
# 2. Install Python 3.7.2:
#
# https://www.python.org/downloads/
#
# 3. Append ";C:\Python36;C:\Python36\Scripts" to the "Path" environment variable:
# 3. Append ";C:\Python37;C:\Python37\Scripts" to the "Path" environment variable:
#
# https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/sysdm_advancd_environmnt_addchange_variable.mspx?mfr=true
#
# 4. In Powershell, run the following commands:
#
# $ pip install 'virtualenv>=15.1.0'
# $ pip install 'virtualenv==16.2.0'
# $ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
#
# 5. Clone the repository:

View File

@@ -9,4 +9,4 @@ if [[ "${?}" != "0" ]]; then
echo "Couldn't get revision of the git repository. Setting to 'unknown' instead"
DOCKER_COMPOSE_GITSHA="unknown"
fi
echo "${DOCKER_COMPOSE_GITSHA}" > compose/GITSHA
echo "${DOCKER_COMPOSE_GITSHA}"

View File

@@ -1,7 +1,5 @@
#!/bin/bash
set -x
curl -f -u$BINTRAY_USERNAME:$BINTRAY_API_KEY -X GET \
https://api.bintray.com/repos/docker-compose/${CIRCLE_BRANCH}
@@ -27,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

View File

@@ -192,6 +192,8 @@ be handled manually by the operator:
- Bump the version in `compose/__init__.py` to the *next* minor version
number with `dev` appended. For example, if you just released `1.4.0`,
update it to `1.5.0dev`
- Update compose_version in [github.com/docker/docker.github.io/blob/master/_config.yml](https://github.com/docker/docker.github.io/blob/master/_config.yml) and [github.com/docker/docker.github.io/blob/master/_config_authoring.yml](https://github.com/docker/docker.github.io/blob/master/_config_authoring.yml)
- Update the release note in [github.com/docker/docker.github.io](https://github.com/docker/docker.github.io/blob/master/release-notes/docker-compose.md)
## Advanced options

View File

@@ -0,0 +1,39 @@
#!/bin/bash
set -e
set -x
## Usage :
## changelog PREVIOUS_TAG..HEAD
# configure refs so we get pull-requests metadata
git config --add remote.origin.fetch +refs/pull/*/head:refs/remotes/origin/pull/*
git fetch origin
RANGE=${1:-"$(git describe --tags --abbrev=0)..HEAD"}
echo "Generate changelog for range ${RANGE}"
echo
pullrequests() {
for commit in $(git log ${RANGE} --format='format:%H'); do
# Get the oldest remotes/origin/pull/* branch to include this commit, i.e. the one to introduce it
git branch -a --sort=committerdate --contains $commit --list 'origin/pull/*' | head -1 | cut -d'/' -f4
done
}
changes=$(pullrequests | uniq)
echo "pull requests merged within range:"
echo $changes
echo '#Features' > CHANGELOG.md
for pr in $changes; do
curl -fs -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/docker/compose/pulls/${pr} \
| jq -r ' select( .labels[].name | contains("kind/feature") ) | "* "+.title' >> CHANGELOG.md
done
echo '#Bugs' >> CHANGELOG.md
for pr in $changes; do
curl -fs -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/docker/compose/pulls/${pr} \
| jq -r ' select( .labels[].name | contains("kind/bug") ) | "* "+.title' >> CHANGELOG.md
done

View File

@@ -15,6 +15,7 @@ from release.const import NAME
from release.const import REPO_ROOT
from release.downloader import BinaryDownloader
from release.images import ImageManager
from release.images import is_tag_latest
from release.pypi import check_pypirc
from release.pypi import pypi_upload
from release.repository import delete_assets
@@ -203,8 +204,9 @@ 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)
img_manager.build_images(repository, files)
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)
return 1
@@ -243,8 +245,9 @@ 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)
img_manager.build_images(repository, files)
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)
return 1
@@ -258,7 +261,8 @@ def finalize(args):
try:
check_pypirc()
repository = Repository(REPO_ROOT, args.repo)
img_manager = ImageManager(args.release)
tag_as_latest = is_tag_latest(args.release)
img_manager = ImageManager(args.release, tag_as_latest)
pr_data = repository.find_release_pr(args.release)
if not pr_data:
raise ScriptError('No PR found for {}'.format(args.release))

View File

@@ -6,4 +6,5 @@ import os
REPO_ROOT = os.path.join(os.path.dirname(__file__), '..', '..', '..')
NAME = 'docker/compose'
COMPOSE_TESTS_IMAGE_BASE_NAME = NAME + '-tests'
BINTRAY_ORG = 'docker-compose'

View File

@@ -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,

View File

@@ -5,18 +5,36 @@ from __future__ import unicode_literals
import base64
import json
import os
import shutil
import docker
from enum import Enum
from .const import NAME
from .const import REPO_ROOT
from .utils import ScriptError
from .utils import yesno
from script.release.release.const import COMPOSE_TESTS_IMAGE_BASE_NAME
class Platform(Enum):
ALPINE = 'alpine'
DEBIAN = 'debian'
def __str__(self):
return self.value
# Checks if this version respects the GA version format ('x.y.z') and not an RC
def is_tag_latest(version):
ga_version = all(n.isdigit() for n in version.split('.')) and version.count('.') == 2
return ga_version and yesno('Should this release be tagged as \"latest\"? [Y/n]: ', default=True)
class ImageManager(object):
def __init__(self, version):
def __init__(self, version, latest=False):
self.docker_client = docker.APIClient(**docker.utils.kwargs_from_env())
self.version = version
self.latest = latest
if 'HUB_CREDENTIALS' in os.environ:
print('HUB_CREDENTIALS found in environment, issuing login')
credentials = json.loads(base64.urlsafe_b64decode(os.environ['HUB_CREDENTIALS']))
@@ -24,16 +42,36 @@ class ImageManager(object):
username=credentials['Username'], password=credentials['Password']
)
def build_images(self, repository, files):
print("Building release images...")
repository.write_git_sha()
distdir = os.path.join(REPO_ROOT, 'dist')
os.makedirs(distdir, exist_ok=True)
shutil.copy(files['docker-compose-Linux-x86_64'][0], distdir)
os.chmod(os.path.join(distdir, 'docker-compose-Linux-x86_64'), 0o755)
print('Building docker/compose image')
def _tag(self, image, existing_tag, new_tag):
existing_repo_tag = '{image}:{tag}'.format(image=image, tag=existing_tag)
new_repo_tag = '{image}:{tag}'.format(image=image, tag=new_tag)
self.docker_client.tag(existing_repo_tag, new_repo_tag)
def get_full_version(self, platform=None):
return self.version + '-' + platform.__str__() if platform else self.version
def get_runtime_image_tag(self, tag):
return '{image_base_image}:{tag}'.format(
image_base_image=NAME,
tag=self.get_full_version(tag)
)
def build_runtime_image(self, repository, platform):
git_sha = repository.write_git_sha()
compose_image_base_name = NAME
print('Building {image} image ({platform} based)'.format(
image=compose_image_base_name,
platform=platform
))
full_version = self.get_full_version(platform)
build_tag = self.get_runtime_image_tag(platform)
logstream = self.docker_client.build(
REPO_ROOT, tag='docker/compose:{}'.format(self.version), dockerfile='Dockerfile.run',
REPO_ROOT,
tag=build_tag,
buildargs={
'BUILD_PLATFORM': platform.value,
'GIT_COMMIT': git_sha,
},
decode=True
)
for chunk in logstream:
@@ -42,9 +80,33 @@ class ImageManager(object):
if 'stream' in chunk:
print(chunk['stream'], end='')
print('Building test image (for UCP e2e)')
if platform == Platform.ALPINE:
self._tag(compose_image_base_name, full_version, self.version)
if self.latest:
self._tag(compose_image_base_name, full_version, platform)
if platform == Platform.ALPINE:
self._tag(compose_image_base_name, full_version, 'latest')
def get_ucp_test_image_tag(self, tag=None):
return '{image}:{tag}'.format(
image=COMPOSE_TESTS_IMAGE_BASE_NAME,
tag=tag or self.version
)
# Used for producing a test image for UCP
def build_ucp_test_image(self, repository):
print('Building test image (debian based for UCP e2e)')
git_sha = repository.write_git_sha()
ucp_test_image_tag = self.get_ucp_test_image_tag()
logstream = self.docker_client.build(
REPO_ROOT, tag='docker-compose-tests:tmp', decode=True
REPO_ROOT,
tag=ucp_test_image_tag,
target='build',
buildargs={
'BUILD_PLATFORM': Platform.DEBIAN.value,
'GIT_COMMIT': git_sha,
},
decode=True
)
for chunk in logstream:
if 'error' in chunk:
@@ -52,26 +114,15 @@ class ImageManager(object):
if 'stream' in chunk:
print(chunk['stream'], end='')
container = self.docker_client.create_container(
'docker-compose-tests:tmp', entrypoint='tox'
)
self.docker_client.commit(container, 'docker/compose-tests', 'latest')
self.docker_client.tag(
'docker/compose-tests:latest', 'docker/compose-tests:{}'.format(self.version)
)
self.docker_client.remove_container(container, force=True)
self.docker_client.remove_image('docker-compose-tests:tmp', force=True)
self._tag(COMPOSE_TESTS_IMAGE_BASE_NAME, self.version, 'latest')
@property
def image_names(self):
return [
'docker/compose-tests:latest',
'docker/compose-tests:{}'.format(self.version),
'docker/compose:{}'.format(self.version)
]
def build_images(self, repository):
self.build_runtime_image(repository, Platform.ALPINE)
self.build_runtime_image(repository, Platform.DEBIAN)
self.build_ucp_test_image(repository)
def check_images(self):
for name in self.image_names:
for name in self.get_images_to_push():
try:
self.docker_client.inspect_image(name)
except docker.errors.ImageNotFound:
@@ -79,8 +130,22 @@ class ImageManager(object):
return False
return True
def get_images_to_push(self):
tags_to_push = {
"{}:{}".format(NAME, self.version),
self.get_runtime_image_tag(Platform.ALPINE),
self.get_runtime_image_tag(Platform.DEBIAN),
self.get_ucp_test_image_tag(),
self.get_ucp_test_image_tag('latest'),
}
if is_tag_latest(self.version):
tags_to_push.add("{}:latest".format(NAME))
return tags_to_push
def push_images(self):
for name in self.image_names:
tags_to_push = self.get_images_to_push()
print('Build tags to push {}'.format(tags_to_push))
for name in tags_to_push:
print('Pushing {} to Docker Hub'.format(name))
logstream = self.docker_client.push(name, stream=True, decode=True)
for chunk in logstream:

View File

@@ -175,6 +175,7 @@ class Repository(object):
def write_git_sha(self):
with open(os.path.join(REPO_ROOT, 'compose', 'GITSHA'), 'w') as f:
f.write(self.git_repo.head.commit.hexsha[:7])
return self.git_repo.head.commit.hexsha[:7]
def cherry_pick_prs(self, release_branch, ids):
if not ids:
@@ -219,7 +220,7 @@ def get_contributors(pr_data):
commits = pr_data.get_commits()
authors = {}
for commit in commits:
if not commit.author:
if not commit or not commit.author or not commit.author.login:
continue
author = commit.author.login
authors[author] = authors.get(author, 0) + 1

View File

@@ -15,7 +15,7 @@
set -e
VERSION="1.24.0"
VERSION="1.25.2-rc1"
IMAGE="docker/compose:$VERSION"
@@ -36,19 +36,19 @@ 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
DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -t"
if [ -t 0 ] && [ -t 1 ]; then
DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -t"
fi
# Always set -i to support piped and terminal input in run/exec
@@ -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 "$@"

View File

@@ -13,13 +13,13 @@ if ! [ ${DEPLOYMENT_TARGET} == "$(macos_version)" ]; then
SDK_SHA1=dd228a335194e3392f1904ce49aff1b1da26ca62
fi
OPENSSL_VERSION=1.1.0j
OPENSSL_VERSION=1.1.1d
OPENSSL_URL=https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
OPENSSL_SHA1=dcad1efbacd9a4ed67d4514470af12bbe2a1d60a
OPENSSL_SHA1=056057782325134b76d1931c48f2c7e6595d7ef4
PYTHON_VERSION=3.6.8
PYTHON_VERSION=3.7.5
PYTHON_URL=https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
PYTHON_SHA1=09fcc4edaef0915b4dedbfb462f1cd15f82d3a6f
PYTHON_SHA1=8b0311d4cca19f0ea9181731189fa33c9f5aedf9
#
# Install prerequisites.
@@ -36,7 +36,7 @@ if ! [ -x "$(command -v python3)" ]; then
brew install python3
fi
if ! [ -x "$(command -v virtualenv)" ]; then
pip install virtualenv
pip3 install virtualenv==16.2.0
fi
#
@@ -50,7 +50,7 @@ mkdir -p ${TOOLCHAIN_PATH}
#
# Set macOS SDK.
#
if [ ${SDK_FETCH} ]; then
if [[ ${SDK_FETCH} && ! -f ${TOOLCHAIN_PATH}/MacOSX${DEPLOYMENT_TARGET}.sdk/SDKSettings.plist ]]; then
SDK_PATH=${TOOLCHAIN_PATH}/MacOSX${DEPLOYMENT_TARGET}.sdk
fetch_tarball ${SDK_URL} ${SDK_PATH} ${SDK_SHA1}
else
@@ -61,7 +61,7 @@ fi
# Build OpenSSL.
#
OPENSSL_SRC_PATH=${TOOLCHAIN_PATH}/openssl-${OPENSSL_VERSION}
if ! [ -f ${TOOLCHAIN_PATH}/bin/openssl ]; then
if ! [[ $(${TOOLCHAIN_PATH}/bin/openssl version) == *"${OPENSSL_VERSION}"* ]]; then
rm -rf ${OPENSSL_SRC_PATH}
fetch_tarball ${OPENSSL_URL} ${OPENSSL_SRC_PATH} ${OPENSSL_SHA1}
(
@@ -77,7 +77,7 @@ fi
# Build Python.
#
PYTHON_SRC_PATH=${TOOLCHAIN_PATH}/Python-${PYTHON_VERSION}
if ! [ -f ${TOOLCHAIN_PATH}/bin/python3 ]; then
if ! [[ $(${TOOLCHAIN_PATH}/bin/python3 --version) == *"${PYTHON_VERSION}"* ]]; then
rm -rf ${PYTHON_SRC_PATH}
fetch_tarball ${PYTHON_URL} ${PYTHON_SRC_PATH} ${PYTHON_SHA1}
(
@@ -87,9 +87,10 @@ if ! [ -f ${TOOLCHAIN_PATH}/bin/python3 ]; then
--datarootdir=${TOOLCHAIN_PATH}/share \
--datadir=${TOOLCHAIN_PATH}/share \
--enable-framework=${TOOLCHAIN_PATH}/Frameworks \
--with-openssl=${TOOLCHAIN_PATH} \
MACOSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET} \
CFLAGS="-isysroot ${SDK_PATH} -I${TOOLCHAIN_PATH}/include" \
CPPFLAGS="-I${SDK_PATH}/usr/include -I${TOOLCHAIN_PATH}include" \
CPPFLAGS="-I${SDK_PATH}/usr/include -I${TOOLCHAIN_PATH}/include" \
LDFLAGS="-isysroot ${SDK_PATH} -L ${TOOLCHAIN_PATH}/lib"
make -j 4
make install PYTHONAPPSDIR=${TOOLCHAIN_PATH}
@@ -97,6 +98,11 @@ if ! [ -f ${TOOLCHAIN_PATH}/bin/python3 ]; then
)
fi
#
# Smoke test built Python.
#
openssl_version ${TOOLCHAIN_PATH}
echo ""
echo "*** Targeting macOS: ${DEPLOYMENT_TARGET}"
echo "*** Using SDK ${SDK_PATH}"

View File

@@ -8,8 +8,7 @@ set -e
docker run --rm \
--tty \
${GIT_VOLUME} \
--entrypoint="tox" \
"$TAG" -e pre-commit
"$TAG" tox -e pre-commit
get_versions="docker run --rm
--entrypoint=/code/.tox/py27/bin/python
@@ -24,7 +23,7 @@ fi
BUILD_NUMBER=${BUILD_NUMBER-$USER}
PY_TEST_VERSIONS=${PY_TEST_VERSIONS:-py27,py36}
PY_TEST_VERSIONS=${PY_TEST_VERSIONS:-py27,py37}
for version in $DOCKER_VERSIONS; do
>&2 echo "Running tests against Docker $version"

View File

@@ -20,6 +20,3 @@ export DOCKER_DAEMON_ARGS="--storage-driver=$STORAGE_DRIVER"
GIT_VOLUME="--volumes-from=$(hostname)"
. script/test/all
>&2 echo "Building Linux binary"
. script/build/linux-entrypoint

View File

@@ -3,17 +3,18 @@
set -ex
TAG="docker-compose:$(git rev-parse --short HEAD)"
TAG="docker-compose:alpine-$(git rev-parse --short HEAD)"
# By default use the Dockerfile, but can be overridden to use an alternative file
# e.g DOCKERFILE=Dockerfile.armhf script/test/default
# e.g DOCKERFILE=Dockerfile.s390x script/test/default
DOCKERFILE="${DOCKERFILE:-Dockerfile}"
DOCKER_BUILD_TARGET="${DOCKER_BUILD_TARGET:-build}"
rm -rf coverage-html
# Create the host directory so it's owned by $USER
mkdir -p coverage-html
docker build -f ${DOCKERFILE} -t "$TAG" .
docker build -f "${DOCKERFILE}" -t "${TAG}" --target "${DOCKER_BUILD_TARGET}" .
GIT_VOLUME="--volume=$(pwd)/.git:/code/.git"
. script/test/all

View File

@@ -31,31 +31,33 @@ def find_version(*file_paths):
install_requires = [
'cached-property >= 1.2.0, < 2',
'docopt >= 0.6.1, < 0.7',
'PyYAML >= 3.10, < 4.3',
'requests >= 2.6.1, != 2.11.0, != 2.12.2, != 2.18.0, < 2.21',
'texttable >= 0.9.0, < 0.10',
'websocket-client >= 0.32.0, < 1.0',
'docker[ssh] >= 3.7.0, < 4.0',
'dockerpty >= 0.4.1, < 0.5',
'docopt >= 0.6.1, < 1',
'PyYAML >= 3.10, < 6',
'requests >= 2.20.0, < 3',
'texttable >= 0.9.0, < 2',
'websocket-client >= 0.32.0, < 1',
'docker[ssh] >= 3.7.0, < 5',
'dockerpty >= 0.4.1, < 1',
'six >= 1.3.0, < 2',
'jsonschema >= 2.5.1, < 3',
'jsonschema >= 2.5.1, < 4',
]
tests_require = [
'pytest',
'pytest < 6',
]
if sys.version_info[:2] < (3, 4):
tests_require.append('mock >= 1.0.1')
tests_require.append('mock >= 1.0.1, < 4')
extras_require = {
':python_version < "3.2"': ['subprocess32 >= 3.5.4, < 4'],
':python_version < "3.4"': ['enum34 >= 1.0.4, < 2'],
':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5'],
':python_version < "3.3"': ['ipaddress >= 1.0.16'],
':sys_platform == "win32"': ['colorama >= 0.4, < 0.5'],
':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5, < 4'],
':python_version < "3.3"': ['backports.shutil_get_terminal_size == 1.0.0',
'ipaddress >= 1.0.16, < 2'],
':sys_platform == "win32"': ['colorama >= 0.4, < 1'],
'socks': ['PySocks >= 1.5.6, != 1.5.7, < 2'],
}

View File

@@ -11,6 +11,7 @@ import subprocess
import time
from collections import Counter
from collections import namedtuple
from functools import reduce
from operator import attrgetter
import pytest
@@ -19,6 +20,7 @@ import yaml
from docker import errors
from .. import mock
from ..helpers import BUSYBOX_IMAGE_WITH_TAG
from ..helpers import create_host_file
from compose.cli.command import get_project
from compose.config.errors import DuplicateOverrideFileFound
@@ -40,12 +42,31 @@ ProcessResult = namedtuple('ProcessResult', 'stdout stderr')
BUILD_CACHE_TEXT = 'Using cache'
BUILD_PULL_TEXT = 'Status: Image is up to date for busybox:latest'
BUILD_PULL_TEXT = 'Status: Image is up to date for busybox:1.27.2'
COMPOSE_COMPATIBILITY_DICT = {
'version': '2.3',
'volumes': {'foo': {'driver': 'default'}},
'networks': {'bar': {}},
'services': {
'foo': {
'command': '/bin/true',
'image': 'alpine:3.10.1',
'scale': 3,
'restart': 'always:7',
'mem_limit': '300M',
'mem_reservation': '100M',
'cpus': 0.7,
'volumes': ['foo:/bar:rw'],
'networks': {'bar': None},
}
},
}
def start_process(base_dir, options):
proc = subprocess.Popen(
['docker-compose'] + options,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=base_dir)
@@ -53,8 +74,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))
@@ -62,6 +83,12 @@ 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, stdin=None):
project_options = project_options or []
proc = start_process(base_dir, project_options + options)
return wait_on_process(proc, returncode=returncode, stdin=stdin)
def wait_on_condition(condition, delay=0.1, timeout=40):
start_time = time.time()
while not condition():
@@ -148,10 +175,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):
project_options = project_options or []
proc = start_process(self.base_dir, project_options + options)
return wait_on_process(proc, returncode=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
@@ -170,6 +195,13 @@ class CLITestCase(DockerClientTestCase):
# Prevent tearDown from trying to create a project
self.base_dir = None
def test_quiet_build(self):
self.base_dir = 'tests/fixtures/build-args'
result = self.dispatch(['build'], None)
quietResult = self.dispatch(['build', '-q'], None)
assert result.stdout != ""
assert quietResult.stdout == ""
def test_help_nonexistent(self):
self.base_dir = 'tests/fixtures/no-composefile'
result = self.dispatch(['help', 'foobar'], returncode=1)
@@ -228,6 +260,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=*'])
@@ -244,7 +287,7 @@ class CLITestCase(DockerClientTestCase):
# assert there are no python objects encoded in the output
assert '!!' not in result.stdout
output = yaml.load(result.stdout)
output = yaml.safe_load(result.stdout)
expected = {
'version': '2.0',
'volumes': {'data': {'driver': 'local'}},
@@ -258,7 +301,7 @@ class CLITestCase(DockerClientTestCase):
'volumes_from': ['service:other:rw'],
},
'other': {
'image': 'busybox:latest',
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'top',
'volumes': ['/data'],
},
@@ -269,7 +312,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_restart(self):
self.base_dir = 'tests/fixtures/restart'
result = self.dispatch(['config'])
assert yaml.load(result.stdout) == {
assert yaml.safe_load(result.stdout) == {
'version': '2.0',
'services': {
'never': {
@@ -298,7 +341,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_network(self):
self.base_dir = 'tests/fixtures/networks'
result = self.dispatch(['-f', 'external-networks.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'networks' in json_result
assert json_result['networks'] == {
'networks_foo': {
@@ -312,7 +355,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_with_dot_env(self):
self.base_dir = 'tests/fixtures/default-env-file'
result = self.dispatch(['config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert json_result == {
'services': {
'web': {
@@ -324,15 +367,30 @@ class CLITestCase(DockerClientTestCase):
'version': '2.4'
}
def test_config_with_env_file(self):
self.base_dir = 'tests/fixtures/default-env-file'
result = self.dispatch(['--env-file', '.env2', 'config'])
json_result = yaml.safe_load(result.stdout)
assert json_result == {
'services': {
'web': {
'command': 'false',
'image': 'alpine:latest',
'ports': ['5644/tcp', '9998/tcp']
}
},
'version': '2.4'
}
def test_config_with_dot_env_and_override_dir(self):
self.base_dir = 'tests/fixtures/default-env-file'
result = self.dispatch(['--project-directory', 'alt/', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert json_result == {
'services': {
'web': {
'command': 'echo uwu',
'image': 'alpine:3.4',
'image': 'alpine:3.10.1',
'ports': ['3341/tcp', '4449/tcp']
}
},
@@ -342,7 +400,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_volume_v2(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v2.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
@@ -358,7 +416,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_volume_v2_x(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v2-x.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
@@ -374,7 +432,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_volume_v3_x(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v3-x.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
@@ -390,7 +448,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_volume_v3_4(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v3-4.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
@@ -406,7 +464,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_external_network_v3_5(self):
self.base_dir = 'tests/fixtures/networks'
result = self.dispatch(['-f', 'external-networks-v3-5.yml', 'config'])
json_result = yaml.load(result.stdout)
json_result = yaml.safe_load(result.stdout)
assert 'networks' in json_result
assert json_result['networks'] == {
'foo': {
@@ -422,7 +480,7 @@ class CLITestCase(DockerClientTestCase):
def test_config_v1(self):
self.base_dir = 'tests/fixtures/v1-config'
result = self.dispatch(['config'])
assert yaml.load(result.stdout) == {
assert yaml.safe_load(result.stdout) == {
'version': '2.1',
'services': {
'net': {
@@ -447,7 +505,7 @@ class CLITestCase(DockerClientTestCase):
self.base_dir = 'tests/fixtures/v3-full'
result = self.dispatch(['config'])
assert yaml.load(result.stdout) == {
assert yaml.safe_load(result.stdout) == {
'version': '3.5',
'volumes': {
'foobar': {
@@ -524,24 +582,23 @@ class CLITestCase(DockerClientTestCase):
self.base_dir = 'tests/fixtures/compatibility-mode'
result = self.dispatch(['--compatibility', 'config'])
assert yaml.load(result.stdout) == {
'version': '2.3',
'volumes': {'foo': {'driver': 'default'}},
'networks': {'bar': {}},
'services': {
'foo': {
'command': '/bin/true',
'image': 'alpine:3.7',
'scale': 3,
'restart': 'always:7',
'mem_limit': '300M',
'mem_reservation': '100M',
'cpus': 0.7,
'volumes': ['foo:/bar:rw'],
'networks': {'bar': None},
}
},
}
assert yaml.load(result.stdout) == COMPOSE_COMPATIBILITY_DICT
@mock.patch.dict(os.environ)
def test_config_compatibility_mode_from_env(self):
self.base_dir = 'tests/fixtures/compatibility-mode'
os.environ['COMPOSE_COMPATIBILITY'] = 'true'
result = self.dispatch(['config'])
assert yaml.load(result.stdout) == COMPOSE_COMPATIBILITY_DICT
@mock.patch.dict(os.environ)
def test_config_compatibility_mode_from_env_and_option_precedence(self):
self.base_dir = 'tests/fixtures/compatibility-mode'
os.environ['COMPOSE_COMPATIBILITY'] = 'false'
result = self.dispatch(['--compatibility', 'config'])
assert yaml.load(result.stdout) == COMPOSE_COMPATIBILITY_DICT
def test_ps(self):
self.project.get_service('simple').create_container()
@@ -616,7 +673,7 @@ class CLITestCase(DockerClientTestCase):
def test_pull_with_digest(self):
result = self.dispatch(['-f', 'digest.yml', 'pull', '--no-parallel'])
assert 'Pulling simple (busybox:latest)...' in result.stderr
assert 'Pulling simple ({})...'.format(BUSYBOX_IMAGE_WITH_TAG) in result.stderr
assert ('Pulling digest (busybox@'
'sha256:38a203e1986cf79639cfb9b2e1d6e773de84002feea2d4eb006b520'
'04ee8502d)...') in result.stderr
@@ -627,7 +684,7 @@ class CLITestCase(DockerClientTestCase):
'pull', '--ignore-pull-failures', '--no-parallel']
)
assert 'Pulling simple (busybox:latest)...' in result.stderr
assert 'Pulling simple ({})...'.format(BUSYBOX_IMAGE_WITH_TAG) in result.stderr
assert 'Pulling another (nonexisting-image:latest)...' in result.stderr
assert ('repository nonexisting-image not found' in result.stderr or
'image library/nonexisting-image:latest not found' in result.stderr or
@@ -654,19 +711,27 @@ 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'])
assert sorted(result.stderr.split('\n'))[1:] == [
'Pulling web (busybox:latest)...',
'Pulling web (busybox:1.27.2)...',
]
def test_pull_with_include_deps(self):
self.base_dir = 'tests/fixtures/links-composefile'
result = self.dispatch(['pull', '--no-parallel', '--include-deps', 'web'])
assert sorted(result.stderr.split('\n'))[1:] == [
'Pulling db (busybox:latest)...',
'Pulling web (busybox:latest)...',
'Pulling db (busybox:1.27.2)...',
'Pulling web (busybox:1.27.2)...',
]
def test_build_plain(self):
@@ -747,6 +812,27 @@ class CLITestCase(DockerClientTestCase):
]
assert not containers
@pytest.mark.xfail(True, reason='Flaky on local')
def test_build_rm(self):
containers = [
Container.from_ps(self.project.client, c)
for c in self.project.client.containers(all=True)
]
assert not containers
self.base_dir = 'tests/fixtures/simple-dockerfile'
self.dispatch(['build', '--no-rm', 'simple'], returncode=0)
containers = [
Container.from_ps(self.project.client, c)
for c in self.project.client.containers(all=True)
]
assert containers
for c in self.project.client.containers(all=True):
self.addCleanup(self.project.client.remove_container, c, force=True)
def test_build_shm_size_build_option(self):
pull_busybox(self.client)
self.base_dir = 'tests/fixtures/build-shm-size'
@@ -786,32 +872,6 @@ class CLITestCase(DockerClientTestCase):
)
assert 'Favorite Touhou Character: hong.meiling' in result.stdout
def test_bundle_with_digests(self):
self.base_dir = 'tests/fixtures/bundle-with-digests/'
tmpdir = pytest.ensuretemp('cli_test_bundle')
self.addCleanup(tmpdir.remove)
filename = str(tmpdir.join('example.dab'))
self.dispatch(['bundle', '--output', filename])
with open(filename, 'r') as fh:
bundle = json.load(fh)
assert bundle == {
'Version': '0.1',
'Services': {
'web': {
'Image': ('dockercloud/hello-world@sha256:fe79a2cfbd17eefc3'
'44fb8419420808df95a1e22d93b7f621a7399fd1e9dca1d'),
'Networks': ['default'],
},
'redis': {
'Image': ('redis@sha256:a84cb8f53a70e19f61ff2e1d5e73fb7ae62d'
'374b2b7392de1e7d77be26ef8f7b'),
'Networks': ['default'],
}
},
}
def test_build_override_dir(self):
self.base_dir = 'tests/fixtures/build-path-override-dir'
self.override_dir = os.path.abspath('tests/fixtures')
@@ -1108,6 +1168,22 @@ class CLITestCase(DockerClientTestCase):
]
assert len(remote_volumes) > 0
@v2_only()
def test_up_no_start_remove_orphans(self):
self.base_dir = 'tests/fixtures/v2-simple'
self.dispatch(['up', '--no-start'], None)
services = self.project.get_services()
stopped = reduce((lambda prev, next: prev.containers(
stopped=True) + next.containers(stopped=True)), services)
assert len(stopped) == 2
self.dispatch(['-f', 'one-container.yml', 'up', '--no-start', '--remove-orphans'], None)
stopped2 = reduce((lambda prev, next: prev.containers(
stopped=True) + next.containers(stopped=True)), services)
assert len(stopped2) == 1
@v2_only()
def test_up_no_ansi(self):
self.base_dir = 'tests/fixtures/v2-simple'
@@ -1380,7 +1456,7 @@ class CLITestCase(DockerClientTestCase):
if v['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
]
assert set([v['Name'].split('/')[-1] for v in volumes]) == set([volume_with_label])
assert set([v['Name'].split('/')[-1] for v in volumes]) == {volume_with_label}
assert 'label_key' in volumes[0]['Labels']
assert volumes[0]['Labels']['label_key'] == 'label_val'
@@ -1495,6 +1571,26 @@ class CLITestCase(DockerClientTestCase):
assert len(db.containers()) == 0
assert len(console.containers()) == 0
def test_up_with_attach_dependencies(self):
self.base_dir = 'tests/fixtures/echo-services-dependencies'
result = self.dispatch(['up', '--attach-dependencies', '--no-color', 'simple'], None)
simple_name = self.project.get_service('simple').containers(stopped=True)[0].name_without_project
another_name = self.project.get_service('another').containers(
stopped=True
)[0].name_without_project
assert '{} | simple'.format(simple_name) in result.stdout
assert '{} | another'.format(another_name) in result.stdout
def test_up_handles_aborted_dependencies(self):
self.base_dir = 'tests/fixtures/abort-on-container-exit-dependencies'
proc = start_process(
self.base_dir,
['up', 'simple', '--attach-dependencies', '--abort-on-container-exit'])
wait_on_condition(ContainerCountCondition(self.project, 0))
proc.wait()
assert proc.returncode == 1
def test_up_with_force_recreate(self):
self.dispatch(['up', '-d'], None)
service = self.project.get_service('simple')
@@ -2045,7 +2141,7 @@ class CLITestCase(DockerClientTestCase):
for _, config in networks.items():
# TODO: once we drop support for API <1.24, this can be changed to:
# assert config['Aliases'] == [container.short_id]
aliases = set(config['Aliases'] or []) - set([container.short_id])
aliases = set(config['Aliases'] or []) - {container.short_id}
assert not aliases
@v2_only()
@@ -2065,7 +2161,7 @@ class CLITestCase(DockerClientTestCase):
for _, config in networks.items():
# TODO: once we drop support for API <1.24, this can be changed to:
# assert config['Aliases'] == [container.short_id]
aliases = set(config['Aliases'] or []) - set([container.short_id])
aliases = set(config['Aliases'] or []) - {container.short_id}
assert not aliases
assert self.lookup(container, 'app')
@@ -2301,6 +2397,7 @@ class CLITestCase(DockerClientTestCase):
assert 'another' in result.stdout
assert 'exited with code 0' in result.stdout
@pytest.mark.skip(reason="race condition between up and logs")
def test_logs_follow_logs_from_new_containers(self):
self.base_dir = 'tests/fixtures/logs-composefile'
self.dispatch(['up', '-d', 'simple'])
@@ -2327,6 +2424,7 @@ class CLITestCase(DockerClientTestCase):
assert '{} exited with code 0'.format(another_name) in result.stdout
assert '{} exited with code 137'.format(simple_name) in result.stdout
@pytest.mark.skip(reason="race condition between up and logs")
def test_logs_follow_logs_from_restarted_containers(self):
self.base_dir = 'tests/fixtures/logs-restart-composefile'
proc = start_process(self.base_dir, ['up'])
@@ -2347,6 +2445,7 @@ class CLITestCase(DockerClientTestCase):
) == 3
assert result.stdout.count('world') == 3
@pytest.mark.skip(reason="race condition between up and logs")
def test_logs_default(self):
self.base_dir = 'tests/fixtures/logs-composefile'
self.dispatch(['up', '-d'])
@@ -2473,10 +2572,12 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['up', '-d'])
assert len(project.get_service('web').containers()) == 2
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 0
self.dispatch(['up', '-d', '--scale', 'web=3'])
self.dispatch(['up', '-d', '--scale', 'web=3', '--scale', 'worker=1'])
assert len(project.get_service('web').containers()) == 3
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 1
def test_up_scale_scale_down(self):
self.base_dir = 'tests/fixtures/scale'
@@ -2485,22 +2586,26 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['up', '-d'])
assert len(project.get_service('web').containers()) == 2
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 0
self.dispatch(['up', '-d', '--scale', 'web=1'])
assert len(project.get_service('web').containers()) == 1
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 0
def test_up_scale_reset(self):
self.base_dir = 'tests/fixtures/scale'
project = self.project
self.dispatch(['up', '-d', '--scale', 'web=3', '--scale', 'db=3'])
self.dispatch(['up', '-d', '--scale', 'web=3', '--scale', 'db=3', '--scale', 'worker=3'])
assert len(project.get_service('web').containers()) == 3
assert len(project.get_service('db').containers()) == 3
assert len(project.get_service('worker').containers()) == 3
self.dispatch(['up', '-d'])
assert len(project.get_service('web').containers()) == 2
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 0
def test_up_scale_to_zero(self):
self.base_dir = 'tests/fixtures/scale'
@@ -2509,10 +2614,12 @@ class CLITestCase(DockerClientTestCase):
self.dispatch(['up', '-d'])
assert len(project.get_service('web').containers()) == 2
assert len(project.get_service('db').containers()) == 1
assert len(project.get_service('worker').containers()) == 0
self.dispatch(['up', '-d', '--scale', 'web=0', '--scale', 'db=0'])
self.dispatch(['up', '-d', '--scale', 'web=0', '--scale', 'db=0', '--scale', 'worker=0'])
assert len(project.get_service('web').containers()) == 0
assert len(project.get_service('db').containers()) == 0
assert len(project.get_service('worker').containers()) == 0
def test_port(self):
self.base_dir = 'tests/fixtures/ports-composefile'
@@ -2592,7 +2699,7 @@ class CLITestCase(DockerClientTestCase):
container, = self.project.containers()
expected_template = ' container {} {}'
expected_meta_info = ['image=busybox:latest', 'name=simple-composefile_simple_']
expected_meta_info = ['image=busybox:1.27.2', 'name=simple-composefile_simple_']
assert expected_template.format('create', container.id) in lines[0]
assert expected_template.format('start', container.id) in lines[1]
@@ -2664,7 +2771,7 @@ class CLITestCase(DockerClientTestCase):
self.base_dir = 'tests/fixtures/extends'
self.dispatch(['up', '-d'], None)
assert set([s.name for s in self.project.services]) == set(['mydb', 'myweb'])
assert set([s.name for s in self.project.services]) == {'mydb', 'myweb'}
# Sort by name so we get [db, web]
containers = sorted(
@@ -2676,15 +2783,9 @@ class CLITestCase(DockerClientTestCase):
web = containers[1]
db_name = containers[0].name_without_project
assert set(get_links(web)) == set(
['db', db_name, 'extends_{}'.format(db_name)]
)
assert set(get_links(web)) == {'db', db_name, 'extends_{}'.format(db_name)}
expected_env = set([
"FOO=1",
"BAR=2",
"BAZ=2",
])
expected_env = {"FOO=1", "BAR=2", "BAZ=2"}
assert expected_env <= set(web.get('Config.Env'))
def test_top_services_not_running(self):
@@ -2739,8 +2840,8 @@ class CLITestCase(DockerClientTestCase):
result = self.dispatch(['images'])
assert 'busybox' in result.stdout
assert 'multiple-composefiles_another_1' in result.stdout
assert 'multiple-composefiles_simple_1' in result.stdout
assert '_another_1' in result.stdout
assert '_simple_1' in result.stdout
@mock.patch.dict(os.environ)
def test_images_tagless_image(self):
@@ -2788,4 +2889,4 @@ class CLITestCase(DockerClientTestCase):
assert re.search(r'foo1.+test[ \t]+dev', result.stdout) is not None
assert re.search(r'foo2.+test[ \t]+prod', result.stdout) is not None
assert re.search(r'foo3.+_foo3[ \t]+latest', result.stdout) is not None
assert re.search(r'foo3.+test[ \t]+latest', result.stdout) is not None

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: ls .

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: ls /thecakeisalie

View File

@@ -0,0 +1,10 @@
version: "2.0"
services:
simple:
image: busybox:1.31.0-uclibc
command: top
depends_on:
- another
another:
image: busybox:1.31.0-uclibc
command: ls /thecakeisalie

View File

@@ -1,4 +1,4 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
LABEL com.docker.compose.test_image=true
ARG favorite_th_character
RUN echo "Favorite Touhou Character: ${favorite_th_character}"

View File

@@ -1,3 +1,3 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
LABEL com.docker.compose.test_image=true
CMD echo "success"

View File

@@ -1,4 +1,4 @@
FROM busybox
FROM busybox:1.31.0-uclibc
# Report the memory (through the size of the group memory)
RUN echo "memory:" $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)

View File

@@ -1,4 +1,4 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
RUN echo a
CMD top

View File

@@ -1,4 +1,4 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
RUN echo b
CMD top

View File

@@ -1,9 +0,0 @@
version: '2.0'
services:
web:
image: dockercloud/hello-world@sha256:fe79a2cfbd17eefc344fb8419420808df95a1e22d93b7f621a7399fd1e9dca1d
redis:
image: redis@sha256:a84cb8f53a70e19f61ff2e1d5e73fb7ae62d374b2b7392de1e7d77be26ef8f7b

View File

@@ -1,7 +1,7 @@
version: '3.5'
services:
foo:
image: alpine:3.7
image: alpine:3.10.1
command: /bin/true
deploy:
replicas: 3

4
tests/fixtures/default-env-file/.env2 vendored Normal file
View File

@@ -0,0 +1,4 @@
IMAGE=alpine:latest
COMMAND=false
PORT1=5644
PORT2=9998

View File

@@ -1,4 +1,4 @@
IMAGE=alpine:3.4
IMAGE=alpine:3.10.1
COMMAND=echo uwu
PORT1=3341
PORT2=4449

View File

@@ -1,4 +1,4 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
LABEL com.docker.compose.test_image=true
VOLUME /data
CMD top

View File

@@ -1,10 +1,10 @@
web:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: "sleep 100"
links:
- db
db:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: "sleep 200"

View File

@@ -0,0 +1,10 @@
version: "2.0"
services:
simple:
image: busybox:1.31.0-uclibc
command: echo simple
depends_on:
- another
another:
image: busybox:1.31.0-uclibc
command: echo another

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: echo simple
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: echo another

View File

@@ -1,4 +1,4 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
LABEL com.docker.compose.test_image=true
ENTRYPOINT ["printf"]
CMD ["default", "args"]

View File

@@ -0,0 +1,2 @@
WHEREAMI
DEFAULT_CONF_LOADED=true

View File

@@ -0,0 +1 @@
WHEREAMI=override

View File

@@ -0,0 +1,6 @@
version: '3.7'
services:
test:
image: busybox
env_file: .env.conf
entrypoint: env

View File

@@ -1,5 +1,5 @@
service:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
environment:

View File

@@ -2,7 +2,7 @@ version: "2.2"
services:
service:
image: busybox:latest
image: busybox:1.27.2
command: top
environment:

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: sh -c "echo hello && tail -f /dev/null"
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: /bin/false

View File

@@ -1,6 +1,6 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
expose:
- '3000'

View File

@@ -1,2 +1,2 @@
FROM busybox:latest
FROM busybox:1.31.0-uclibc
RUN touch /foo

View File

@@ -8,3 +8,4 @@ services:
image: test:prod
foo3:
build: .
image: test:latest

View File

@@ -1,11 +1,11 @@
db:
image: busybox:latest
image: busybox:1.27.2
command: top
web:
image: busybox:latest
image: busybox:1.27.2
command: top
links:
- db:db
console:
image: busybox:latest
image: busybox:1.27.2
command: top

View File

@@ -1,9 +1,9 @@
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
log_driver: "none"
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
log_driver: "json-file"
log_opt:

View File

@@ -1,12 +1,12 @@
version: "2"
services:
simple:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
logging:
driver: "none"
another:
image: busybox:latest
image: busybox:1.31.0-uclibc
command: top
logging:
driver: "json-file"

Some files were not shown because too many files have changed in this diff Show More