Compare commits

...

225 Commits
1.27.3 ... v1

Author SHA1 Message Date
aevesdocker
0d4edbbd19 Change links and add versioning information
Signed-off-by: aevesdocker <allie.sadler@docker.com>
2024-05-01 14:52:41 +02:00
aevesdocker
fe42107f41 Add legacy reference files
Signed-off-by: aevesdocker <allie.sadler@docker.com>
2024-05-01 14:52:41 +02:00
Laura Brehm
30fcb72cf3 Merge pull request #9625 from laurazard/master
Update README.md of V1 branch to warn about V1 end-of-life
2022-07-04 19:45:45 +01:00
Laura Brehm
db94eb0c26 Add end-of-life message to issue templates
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-07-04 17:57:08 +01:00
Laura Brehm
c9527747eb Change wording about V2 GA being on the way for consistency.
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-07-04 17:43:50 +01:00
Laura Brehm
58dc3ad3c1 Update README.md of V1 branch to warn about V1 end-of-life
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-07-04 17:19:33 +01:00
Guillaume Lours
9f2fd6f358 Merge pull request #9418 from glours/update-v1-install
Update the installation guide for the python version of Compose
2022-04-26 17:45:19 +02:00
Guillaume Lours
b750e5bb4c Update the installation guide for the python version of Compose
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-04-26 17:44:45 +02:00
Ulysses Souza
6eb51d3b5b Merge pull request #8644 from yariksheptykin/patch-1
Explain `--filter` in `ps`
2021-10-15 06:44:19 +02:00
Nicolas De Loof
f35db7f31b document End of Life policy
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-22 09:00:40 +02:00
Iaroslav Sheptykin
cd97ac0fc1 Explain --filter in ps
Explain `--filter` option of compse `ps` in more detail.

Signed-off-by: Iaroslav Sheptykin <i.sheptykin@neusta.de>
2021-09-20 21:35:05 +02:00
Nicolas De Loof
2011bc3cea exclude .github from pre-commit
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-09 15:43:15 +02:00
Nicolas De Loof
7c82d8ad2c only run CI workflow when PR target is branch v2
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-09 10:49:39 +02:00
Nicolas De Loof
d06e15323a add official logo as vector graphic
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-06 08:59:59 +02:00
Nicolas De Loof
fa7a7e2cb5 setup compose v2 release workflow
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-02 13:14:42 +02:00
Nicolas De Loof
3e797d6544 setup CI for compose v2
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-02 09:01:31 +02:00
Nicolas De Loof
60856228ea document Compose v2 coming soon
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-09-01 16:28:11 +02:00
Ulysses Souza
4a51af09d6 Merge pull request #8301 from docker/dependabot/add-v2-config-file
Upgrade to GitHub-native Dependabot
2021-06-18 13:29:41 -03:00
Ulysses Souza
318181b21e Merge pull request #7718 from docker/dependabot/pip/paramiko-2.7.2
Bump paramiko from 2.7.1 to 2.7.2
2021-06-15 18:45:33 -03:00
Ulysses Souza
4d5aab95d1 Merge pull request #7728 from docker/dependabot/pip/texttable-1.6.3
Bump texttable from 1.6.2 to 1.6.3
2021-06-15 15:41:50 -03:00
dependabot-preview[bot]
53237b9f9c Bump texttable from 1.6.2 to 1.6.3
Bumps [texttable](https://github.com/foutaise/texttable) from 1.6.2 to 1.6.3.
- [Release notes](https://github.com/foutaise/texttable/releases)
- [Changelog](https://github.com/foutaise/texttable/blob/master/CHANGELOG.md)
- [Commits](https://github.com/foutaise/texttable/compare/v1.6.2...v1.6.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 17:27:15 +00:00
Ulysses Souza
2a485a02de Merge pull request #8008 from docker/dependabot/pip/requests-2.25.1
Bump requests from 2.24.0 to 2.25.1
2021-06-15 14:26:09 -03:00
dependabot-preview[bot]
e815126c68 Bump paramiko from 2.7.1 to 2.7.2
Bumps [paramiko](https://github.com/paramiko/paramiko) from 2.7.1 to 2.7.2.
- [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.7.1...2.7.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 16:58:29 +00:00
dependabot-preview[bot]
872e7025a0 Bump requests from 2.24.0 to 2.25.1
Bumps [requests](https://github.com/psf/requests) from 2.24.0 to 2.25.1.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/master/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.24.0...v2.25.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 16:57:42 +00:00
Ulysses Souza
e6db77b073 Merge pull request #8356 from docker/dependabot/pip/pywin32-301
Bump pywin32 from 227 to 301
2021-06-15 13:57:09 -03:00
Ulysses Souza
cc97ce94b5 Merge pull request #8357 from docker/dependabot/pip/certifi-2021.5.30
Bump certifi from 2020.6.20 to 2021.5.30
2021-06-15 13:56:50 -03:00
Ulysses Souza
addfb6c2b2 Merge pull request #8381 from docker/dependabot/pip/websocket-client-1.1.0
Bump websocket-client from 0.57.0 to 1.1.0
2021-06-15 13:56:28 -03:00
Nicolas De Loof
ce8e6d0a5f warning about wrong repo being used to report issues
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-06-15 17:46:25 +02:00
dependabot-preview[bot]
e5358f273b Bump certifi from 2020.6.20 to 2021.5.30
Bumps [certifi](https://github.com/certifi/python-certifi) from 2020.6.20 to 2021.5.30.
- [Release notes](https://github.com/certifi/python-certifi/releases)
- [Commits](https://github.com/certifi/python-certifi/compare/2020.06.20...2021.05.30)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 15:20:45 +00:00
dependabot-preview[bot]
a091f468d6 Bump pywin32 from 227 to 301
Bumps [pywin32](https://github.com/mhammond/pywin32) from 227 to 301.
- [Release notes](https://github.com/mhammond/pywin32/releases)
- [Changelog](https://github.com/mhammond/pywin32/blob/master/CHANGES.txt)
- [Commits](https://github.com/mhammond/pywin32/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 15:19:51 +00:00
dependabot-preview[bot]
acb91db8a6 Bump websocket-client from 0.57.0 to 1.1.0
Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 0.57.0 to 1.1.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.57.0...v1.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-15 15:19:49 +00:00
Ulysses Souza
dfe472118d Merge pull request #8318 from docker/dependabot/pip/pytest-6.2.4
Bump pytest from 6.0.1 to 6.2.4
2021-06-15 12:19:31 -03:00
Ulysses Souza
947953143c Merge pull request #7983 from docker/dependabot/pip/colorama-0.4.4
Bump colorama from 0.4.3 to 0.4.4
2021-06-15 12:19:18 -03:00
Ulysses Souza
2791d31cfb Merge pull request #8273 from docker/dependabot/pip/ddt-1.4.2
Bump ddt from 1.4.1 to 1.4.2
2021-06-15 12:18:53 -03:00
Ulysses Souza
a99377720c Merge pull request #8358 from docker/dependabot/pip/urllib3-1.26.5
Bump urllib3 from 1.25.10 to 1.26.5
2021-06-15 12:18:26 -03:00
dependabot-preview[bot]
b8f292bbed Bump urllib3 from 1.25.10 to 1.26.5
Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.25.10 to 1.26.5.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/1.25.10...1.26.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-05-31 21:26:25 +00:00
Ulysses Souza
73f8cf9132 Merge pull request #8317 from ulyssessouza/post-release-1.29.2
Post release 1.29.2
2021-05-11 17:54:04 -03:00
dependabot-preview[bot]
53add5f372 Bump pytest from 6.0.1 to 6.2.4
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.1 to 6.2.4.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.1...6.2.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-05-10 21:17:06 +00:00
Ulysses Souza
203576363e Remove section mentioning _config_authoring on docs
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-05-10 17:26:17 -03:00
Ulysses Souza
0eaf57466d Update changelog to 1.29.2
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-05-10 17:25:50 -03:00
Ulysses Souza
96a8e3b3c5 Merge pull request #8316 from ulyssessouza/bump-py
Bump py to 1.10.0
2021-05-10 07:09:21 -03:00
Ulysses Souza
aca6edd631 Merge pull request #8313 from ulyssessouza/remove-compose-v2-msg
Remove advertisement for `docker compose` from up
2021-05-10 06:55:42 -03:00
Ulysses Souza
39ab3aee50 Bump py to 1.10.0
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-05-10 06:44:49 -03:00
Ulysses Souza
39c2d42a0e Remove advertisement for docker compose from up
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-05-07 01:41:47 -03:00
dependabot-preview[bot]
397ca0764c Upgrade to GitHub-native Dependabot 2021-04-28 16:46:16 +00:00
Ulysses Souza
aa45dedb3d Merge pull request #8288 from aiordache/release_1.29.1
1.29.1 Post-release updates
2021-04-15 11:41:14 -03:00
Anca Iordache
afb36f236b 1.29.1 Post-release updates
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-15 15:07:50 +02:00
Ulysses Souza
f01e535cf4 Merge pull request #8290 from aiordache/flaky_tests
Update flaky tests on inter-service dependencies
2021-04-15 10:04:06 -03:00
Ulysses Souza
853efbfb54 Merge pull request #8281 from aiordache/Jenkins_update
Update node spec in Jenkinsfile and Docker config mount
2021-04-15 10:03:45 -03:00
Anca Iordache
6ea24001fa mkdir .docker directory before copying the config
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-15 14:16:05 +02:00
Anca Iordache
c3d8e558a2 update path
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-15 13:58:58 +02:00
Anca Iordache
8f9f1111f3 Copy the .docker/config to dind container for authentication
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-15 12:23:17 +02:00
Anca Iordache
1b42ecba14 Update flaky tests on inter-service dependencies
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-15 10:44:32 +02:00
Anca Iordache
adae403b27 Merge pull request #8261 from ulyssessouza/metrics-nosuchcommand
Ignore command names on NoSuchCommand exceptions
2021-04-13 19:38:15 +02:00
Ulysses Souza
0bea52b18d Merge pull request #8280 from aiordache/ipc_recreate
Add IPC mode to the config hash
2021-04-13 14:19:32 -03:00
Ulysses Souza
2d0c9366ff Merge pull request #8279 from aiordache/max_replicas
Add placement.max_replicas_per_node to conversion map
2021-04-13 14:18:42 -03:00
Anca Iordache
8a6dc88f9e Merge pull request #8278 from ulyssessouza/revert-scan-msg
Revert "Add Snyk scan suggestion when building"
2021-04-13 18:52:10 +02:00
Anca Iordache
d79745a2cd hardcode path to docker config
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-13 18:10:59 +02:00
Anca Iordache
1250bb7481 Update node spec in Jenkinsfile
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-13 17:11:29 +02:00
Anca Iordache
3ba41b98d3 Add Ipc mode to the config hash
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-13 16:47:42 +02:00
Anca Iordache
7f7370b811 Add placement.max_replicas_per_node to conversion map
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-13 15:55:22 +02:00
Ulysses Souza
a9e8ae190f Revert "Add Snyk scan suggestion when building"
This reverts commit e496c64127.

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-04-13 10:34:06 -03:00
dependabot-preview[bot]
2c6f4b7028 Bump ddt from 1.4.1 to 1.4.2
Bumps [ddt](https://github.com/datadriventests/ddt) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/datadriventests/ddt/releases)
- [Commits](https://github.com/datadriventests/ddt/compare/1.4.1...1.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-04-12 21:21:44 +00:00
Nicolas De Loof
3eee3e093a change builder API to return imageID
this allows more flexibility running CLI builder, especially we don't
have anymore to parse build output to get build status/imageID and can
pass the console FDs to buildkit

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2021-04-09 19:29:25 +02:00
Anca Iordache
ad770b272c Merge pull request #8258 from ulyssessouza/bump-1.29.0
Bump 1.29.0
2021-04-09 14:21:03 +01:00
Ulysses Souza
e5cab3ced5 Ignore command names on NoSuchCommand exceptions
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-04-07 20:20:14 -03:00
Ulysses Souza
7984767db2 Bump 1.29.0
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-04-06 18:41:34 -03:00
Anca Iordache
c81046aac0 Merge pull request #8239 from timoxley/patch-1
Mention `--ansi never` in `--no-ansi` deprecation
2021-04-06 19:04:25 +01:00
Tim Kevin Oxley
84c816e887 Mention --ansi never in --no-ansi deprecation
Ideally deprecation messages should point users directly at the non-deprecated alternative so it's a no-brainer for someone to switch to it.

Signed-off-by: Tim Kevin Oxley <secoif@gmail.com>
2021-04-06 14:59:34 -03:00
dependabot-preview[bot]
5b6c3e8389 Bump colorama from 0.4.3 to 0.4.4
Bumps [colorama](https://github.com/tartley/colorama) from 0.4.3 to 0.4.4.
- [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.3...0.4.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-04-06 17:49:36 +00:00
Anca Iordache
1607674374 Merge pull request #8256 from ulyssessouza/bump-py-5
Bump docker-py to 5.0.0 and PyYAML to 5.4.1
2021-04-06 18:48:20 +01:00
Anca Iordache
683fac0dbf Merge pull request #8122 from ojab/add_init_containers
Add init container support
2021-04-06 18:25:24 +01:00
Ulysses Souza
ddee2958ec Bump docker-py to 5.0.0 and PyYAML to 5.4.1
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-04-06 14:24:48 -03:00
Anca Iordache
1ab1cd202b Merge pull request #8091 from docker/dependabot/pip/packaging-20.9
Bump packaging from 20.4 to 20.9
2021-04-06 18:18:25 +01:00
Anca Iordache
1752927dcd Merge pull request #8183 from docker/dependabot/pip/coverage-5.5
Bump coverage from 5.2.1 to 5.5
2021-04-06 18:13:21 +01:00
Anca Iordache
c2ddd71e5f Merge pull request #8232 from aiordache/release_1.28.6
Update changelog for 1.28.6
2021-04-06 18:11:52 +01:00
Anca Iordache
72bbd9c3a6 Merge pull request #8253 from docker/dependabot/pip/python-dotenv-0.17.0
Bump python-dotenv from 0.14.0 to 0.17.0
2021-04-06 18:10:04 +01:00
Anca Iordache
3c9ee678e7 Merge pull request #8247 from ulyssessouza/scan-suggestion
Add Snyk scan suggestion when building
2021-04-06 10:09:07 +01:00
dependabot-preview[bot]
92fefbc9cc Bump python-dotenv from 0.14.0 to 0.17.0
Bumps [python-dotenv](https://github.com/theskumar/python-dotenv) from 0.14.0 to 0.17.0.
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/theskumar/python-dotenv/compare/v0.14.0...v0.17.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-04-05 21:23:08 +00:00
Ulysses Souza
e496c64127 Add Snyk scan suggestion when building
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-04-05 12:34:45 -03:00
Chris Crone
84afa518e8 Merge pull request #8061 from albers/completion-profiles
Add bash completion for profiles and a command to list profiles
2021-03-30 09:33:50 +02:00
Anca Iordache
0f6a55e036 Update changelog for 1.28.6
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-23 15:18:15 +01:00
Anca Iordache
8ce5e235e4 Add back storage_opts as service property
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-23 11:02:51 +01:00
Anca Iordache
c1dddbe608 Merge pull request #8213 from ulyssessouza/fix-exec-error-msg
Fix on removing error message on 'exec' error
2021-03-19 09:45:34 +01:00
Anca Iordache
981b0cd641 Merge pull request #8178 from mgorny/cached-prop-dep
Use built-in functools.cached_property when possible
2021-03-18 20:17:49 +01:00
Ulysses Souza
5ec8af582c Fix on removing error message on 'exec' error
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-03-17 17:49:15 -03:00
Anca Iordache
f5342b600c Add compose.yaml/.yml to default filenames
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-16 18:04:51 +01:00
Anca Iordache
4a26d95de4 Make --env-file paths relative to current working directory
Look up compose files in project dir as fallback to no compose file in current working directory
Update config and env-file tests
 - get_default_config does not raise error anymore, returns None if no compose file is found

Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-16 18:04:51 +01:00
Ulysses Souza
5b7851f55b Merge pull request #8188 from aiordache/build_context
Do not use context as base dir for Dockerfile when context is a git url
2021-03-11 13:01:07 +01:00
Anca Iordache
eaa22df151 Do not use context as base dir for Dockerfile when context is a git url
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-09 19:21:08 +01:00
Ulysses Souza
551f680751 Merge pull request #8187 from aiordache/build_opts
Fix build.extra_hosts list format
2021-03-09 19:20:51 +01:00
Anca Iordache
3e071ec8d9 Fix build.extra_hosts list format
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-03-09 18:30:47 +01:00
dependabot-preview[bot]
858ff26731 Bump coverage from 5.2.1 to 5.5
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.2.1 to 5.5.
- [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-5.2.1...coverage-5.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-08 22:20:16 +00:00
Michał Górny
2a7c06a050 Use built-in functools.cached_property when possible
The cached_property decorator is built-in in functools module since
Python 3.8.  Use the external cached_property package only for older
versions of Python.

Signed-off-by: Michał Górny <mgorny@gentoo.org>
2021-03-06 18:45:59 +01:00
Ulysses Souza
d0b7bc3110 Merge pull request #8160 from aiordache/changelog_1.28.5
Update changelog for 1.28.5
2021-03-02 14:14:56 -03:00
Anca Iordache
fe4f16e448 Merge pull request #8166 from ulyssessouza/advertise-space-compose
Advertise `docker compose` for non linux users
2021-03-02 18:05:10 +01:00
Ulysses Souza
1da4301650 Advertise docker compose for non linux users
This adds messages on:
- Root command (only `docker-compose`)
- Command not found
- `help` command

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-03-02 11:14:07 -03:00
aiordache
c594cb3fc3 Update changelog post-release 1.28.5
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-26 10:38:59 +01:00
Anca Iordache
89ad637d50 Merge pull request #8158 from ulyssessouza/fix-log-driver-none
Stop logging when log_driver is set to 'none'
2021-02-25 17:47:35 +01:00
Ulysses Souza
6ca2aed7ec Stop logging when log_driver is set to 'none'
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-25 13:16:39 -03:00
Anca Iordache
fc744a0cc9 Merge pull request #8156 from ulyssessouza/remove-native-log
Remove log.info for native build
2021-02-25 16:05:32 +01:00
Anca Iordache
245ede1d75 Merge pull request #8113 from joselfr/master
Add missing --add-host args to the build command
2021-02-25 15:54:54 +01:00
José Rodrigues
72f7b086d7 Add missing --add-host args to the build command
Signed-off-by: José Rodrigues <contact.jrodrigues@gmail.com>
2021-02-25 11:23:38 -03:00
Ulysses Souza
2f48b6f5e9 Remove log.info for native build
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-25 11:18:31 -03:00
Anca Iordache
e6fcde422c Merge pull request #8153 from aiordache/openssl_mismatch_bug
Fix openssl mismatch bug via docker-py bump (fix in docker-py 4.4.4)
2021-02-25 14:21:53 +01:00
Anca Iordache
75b2d7905f Merge pull request #8138 from aiordache/changelog_update_1.28.4
Update changelog for release 1.28.4
2021-02-24 18:33:04 +01:00
aiordache
efa5969086 Bump docker-py version to 4.4.4
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-24 18:26:12 +01:00
Ulysses Souza
2a4aca7f54 Merge pull request #8147 from aiordache/platform_build
Set `platform` and `isolation` options for cli builder
2021-02-23 09:11:10 -03:00
aiordache
9c8f5a5705 Set platform and isolation options for cli builder
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-23 09:50:45 +01:00
aiordache
62bbc5cfe2 Changelog update post-release 1.28.4
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-19 09:54:39 +01:00
Anca Iordache
66375c2871 Merge pull request #8135 from aiordache/test_auth
Fix docker/config path in the test containers
2021-02-18 19:36:21 +01:00
aiordache
c760600a65 fix config path for authentication
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-18 19:22:13 +01:00
Slava Kardakov
4daad056c4 Add init container support
Fixes #6855

See https://github.com/compose-spec/compose-spec/pull/134

Signed-off-by: Slava Kardakov <ojab@ojab.ru>
2021-02-18 17:47:59 +00:00
Ulysses Souza
74c09cac66 Merge pull request #8134 from aiordache/bump_docker_setup
Bump docker-py to 4.4.3 in setup.py
2021-02-18 13:27:42 -03:00
aiordache
36e470d640 Bump docker-py to 4.4.3 in setup.py
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-18 17:19:46 +01:00
aiordache
d28d717884 Fix SSH port parsing via docker-py bump
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-18 12:52:29 -03:00
Anca Iordache
42c2cfd7a6 Merge pull request #8133 from docker/fix-release-jenkins
Add cgroup1 as filter label
2021-02-18 16:51:55 +01:00
Ulysses Souza
5b983ac653 Add cgroup1 as filter label
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-18 12:24:04 -03:00
Anca Iordache
93425218eb Merge pull request #8130 from docker/fix-release-jenkins
Add label amd64 to filter the agents
2021-02-18 15:58:19 +01:00
aiordache
49d0ee2de5 Update changelog for release 1.28.3
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-18 11:48:29 -03:00
Ulysses Souza
a92c6d7e17 Add label amd64 to filter the agents
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-18 11:34:03 -03:00
Anca Iordache
b8800db52e Merge pull request #8129 from ulyssessouza/bump-python
Bump python to 3.7.10
2021-02-18 15:09:42 +01:00
Ulysses Souza
ccabfde353 Bump python to 3.7.10
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-18 11:04:25 -03:00
aiordache
3297bb50bb Update dind setup for tests
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-17 12:52:14 -03:00
Anca Iordache
e688006444 Merge pull request #8123 from ulyssessouza/fix-dict-access
Fix dics access on keep-prefix option for up
2021-02-16 20:16:50 +01:00
Ulysses Souza
e4a83c15ff Fix dics access on keep-prefix option for up
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-16 15:55:39 -03:00
Anca Iordache
824b9f138e Merge pull request #8094 from Agrendalath/agrendalath/fix_fish_completion
Fix fish completion
2021-02-16 19:48:09 +01:00
Anca Iordache
8654eb2ea3 Merge pull request #8120 from ulyssessouza/bump-docker-py
Bump docker-py
2021-02-15 18:54:30 +01:00
Ulysses Souza
9407ee65e5 Bump docker-py
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-02-15 14:19:37 -03:00
Anca Iordache
66c6d2757a Merge pull request #8082 from thaJeztah/remove_log_driver_check
Remove local check for log-driver read support
2021-02-15 17:07:34 +01:00
Anca Iordache
17daa93edf Merge pull request #8109 from docker/dependabot/pip/cryptography-3.3.2
[Security] Bump cryptography from 3.2.1 to 3.3.2
2021-02-15 16:41:42 +01:00
dependabot-preview[bot]
9795e39d0c [Security] Bump cryptography from 3.2.1 to 3.3.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.2.1 to 3.3.2. **This update includes a security fix.**
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.2.1...3.3.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-12 10:45:09 +00:00
Anca Iordache
393abc5b33 Merge pull request #8112 from aiordache/update_Jenkinsfile
Update test base image in Jenkinsfile
2021-02-12 11:33:06 +01:00
aiordache
d0866c8c18 Update test base image in Jenkinsfile
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-02-10 15:06:06 +01:00
Anca Iordache
546133c977 Merge pull request #8093 from JimCronqvist/master
Fix incorrect CLI env variable name for service profiles
2021-02-10 12:24:02 +01:00
Ulysses Souza
9a2f94713e Merge pull request #8080 from aiordache/update_changelog_1.28.2
Post-release 1.28.2 changelog updates
2021-02-09 16:36:27 -03:00
Agrendalath
b88f635514 Fix fish completion
Signed-off-by: Agrendalath <piotr@surowiec.it>
2021-02-03 00:29:16 +01:00
Jim Cronqvist
31002aeacd Fix incorrect CLI variable name for service profiles
Changed from singular to plural as defined in the docs, i.e. "COMPOSE_PROFILES"

Signed-off-by: Jim Cronqvist <jim.cronqvist@gmail.com>
2021-02-02 21:41:57 +01:00
dependabot-preview[bot]
6209baccf3 Bump packaging from 20.4 to 20.9
Bumps [packaging](https://github.com/pypa/packaging) from 20.4 to 20.9.
- [Release notes](https://github.com/pypa/packaging/releases)
- [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pypa/packaging/compare/20.4...20.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-01 22:22:56 +00:00
Sebastiaan van Stijn
28f8b8549d Remove local check for log-driver read support
Starting with Docker 20.10, the docker daemon has support for
"dual logging", which allows reading back logs, irregardless of
the logging-driver that is configured (except for "none" as logging
driver).

This patch removes the local check, which used a hard-coded list of
logging drivers that are expected to support reading logs.

When using an older version of Docker, the API should return an
error that reading logs is not supported, so no local check should
be needed.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-01-28 16:55:36 +01:00
aiordache
76a19ec8c5 Post-release changelog update
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-01-28 10:28:47 +01:00
Anca Iordache
bba8cd0322 Merge pull request #8045 from aiordache/changelog_1.28.0
Post-release 1.28.0: Update changelog and version
2021-01-26 21:07:24 +01:00
Anca Iordache
f2ec6a2176 Merge pull request #8070 from aiordache/Jenkins_cgroup1_label
Add `cgroup1` label to Release.Jenkinsfile
2021-01-25 19:11:50 +01:00
aiordache
7f7f1607de Add cgroup1 label to Release.Jenkinsfile
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-01-25 19:00:39 +01:00
Anca Iordache
4990a7f935 Merge pull request #8067 from albers/completion-no-log-prefix
Add bash completion for `docker-compose logs|up --no-log-prefix`, fix formatting of help message
2021-01-25 15:06:34 +01:00
Anca Iordache
72f8551466 Merge pull request #8058 from docker/py-37-revert
Revert to Python 3.7 bump for Linux static builds
2021-01-25 14:34:42 +01:00
Harald Albers
487779960c Fix formatting of help output for up|logs --no-log-prefix
Signed-off-by: Harald Albers <github@albersweb.de>
2021-01-24 22:19:37 +00:00
Harald Albers
99b6776fd2 Add bash completion for logs|up --no-log-prefix
This adds bash completion for https://github.com/docker/compose/pull/7435

Signed-off-by: Harald Albers <github@albersweb.de>
2021-01-24 22:18:36 +00:00
Harald Albers
4e382b9c28 Add bash completion for --profile
Signed-off-by: Harald Albers <github@albersweb.de>
2021-01-22 19:24:15 +00:00
Harald Albers
862107a32a Add option for listing service profiles
For command completion of `docker-compose --profile`, we need a portable
way to get a list of profiles used in the current config.

This commit adds a new option `docker-compose config --profiles`.

Signed-off-by: Harald Albers <github@albersweb.de>
2021-01-22 19:24:15 +00:00
Chris Crone
6a3af5b707 build.linux: Revert to Python 3.7
This allows us to revert from Debian Buster to Stretch which allows
us to relax the glibc version requirements.

Signed-off-by: Chris Crone <christopher.crone@docker.com>
2021-01-22 11:35:37 +01:00
aiordache
205d520805 Post-release 1.28.0: update changelog and version
Signed-off-by: aiordache <anca.iordache@docker.com>
2021-01-20 11:30:25 +01:00
Anca Iordache
8f2bb66e73 Merge pull request #8043 from docker/update-compose-spec
Update compose-spec
2021-01-19 19:00:43 +01:00
Ulysses Souza
af4eaae006 Update compose-spec
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-01-19 14:57:59 -03:00
Anca Iordache
1c547b270e Merge pull request #8042 from docker/fix-docker-version
Remove restriction on docker version
2021-01-19 18:37:22 +01:00
Ulysses Souza
1c499bb2eb Remove restriction on docker version
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-01-19 14:33:16 -03:00
Mike Seplowitz
4fa72a066a Improve control over ANSI output (#6858)
* Move global console_handler into function scope

Signed-off-by: Mike Seplowitz <mseplowitz@bloomberg.net>

* Improve control over ANSI output

- Disabled parallel logger ANSI output if not attached to a tty.
  The console handler and progress stream already checked whether the
  output stream is a tty, but ParallelStreamWriter did not.

- Added --ansi=(never|always|auto) option to allow clearer control over
  ANSI output. Since --no-ansi is the same as --ansi=never, --no-ansi is
  now deprecated.

Signed-off-by: Mike Seplowitz <mseplowitz@bloomberg.net>
2021-01-19 18:17:55 +01:00
Anca Iordache
b9249168bd Merge pull request #7926 from maaarghk/no_build_cache_from_duplicate_check
Remove duplicate values check for build.cache_from
2021-01-11 18:33:16 +01:00
Anca Iordache
e36ac32120 Merge pull request #7978 from thaJeztah/default_to_cli_build
Make COMPOSE_DOCKER_CLI_BUILD=1 the default
2021-01-11 18:29:42 +01:00
Guillaume Tardif
5be6bde76c Merge pull request #7989 from docker/add-metrics
Add metrics capturing
2021-01-06 09:38:52 +01:00
guillaume.tardif
c380604a9e Support windows npipe, set content type & corrrect URL /usage. Also fixed socket name for desktop mac
Signed-off-by: guillaume.tardif <guillaume.tardif@gmail.com>
2021-01-05 15:45:10 +01:00
Ulysses Souza
369eb3220a Add metrics
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-01-04 15:16:51 -03:00
Ulysses Souza
2e273c5029 Merge pull request #8005 from asterite3/up-only-attach-foreground-services
Only attach services we're going to read logs from in "up"
2021-01-04 13:44:12 +00:00
Anca Iordache
21e196f20a Merge pull request #8009 from ulyssessouza/fix-windows-popen
Avoid setting unsuported parameter for subprocess.Popen on Windows
2021-01-04 09:55:53 +01:00
Ulysses Souza
b9d86f4b51 Avoid setting unsuported parameter for subprocess.Popen on Windows
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-12-22 17:52:24 -03:00
Daniil Sigalov
1b5278f977 Only attach services we'll read logs from in up
When 'up' is run with explicit list of services, compose will
start them together with their dependencies. It will attach to all
started services, but won't read output from dependencies (their
logs are not printed by 'up') - so the receive buffer of
dependencies will fill and at some point will start blocking those
services. Fix that by only attaching to services given in the
list.
To do that, move logic of choosing which services to attach from
cli/main.py to utils.py and use it from project.py to decide if
service should be attached.

Fixes #6018

Signed-off-by: Daniil Sigalov <asterite@seclab.cs.msu.ru>
2020-12-20 15:58:58 +03:00
Sebastiaan van Stijn
affb0d504d Make COMPOSE_DOCKER_CLI_BUILD=1 the default
This changes compose to use "native" build through the CLI
by default. With this, docker-compose can take advantage of
BuildKit (which is now enabled by default on Docker Desktop
2.5 and up).

Users that want to use the python client for building can
opt-out of this feature by setting COMPOSE_DOCKER_CLI_BUILD=0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-12-08 12:26:41 +01:00
Anca Iordache
8034bc3bd6 Merge pull request #7977 from docker/bumps-virtenv-gitpython
Bump virtualenv from 20.0.30 to 20.2.2 and gitpython to 3.1.11
2020-12-07 19:59:16 +01:00
dependabot-preview[bot]
89fcfc5499 Bump virtualenv from 20.0.30 to 20.2.2
Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
(cherry picked from commit 8785279ffd)
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-12-07 15:57:24 -03:00
Anca Iordache
40a4ec1624 Merge pull request #7679 from docker/dependabot/pip/bcrypt-3.2.0
Bump bcrypt from 3.1.7 to 3.2.0
2020-12-07 19:18:30 +01:00
Anca Iordache
6c55ef6a5d Revert "Bump virtualenv from 20.0.30 to 20.2.1" (#7975)
This reverts commit 8785279ffd.

Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-04 17:32:14 +01:00
Anca Iordache
3f46dc1d76 Revert "Bump gitpython from 3.1.7 to 3.1.11" (#7974)
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-04 17:22:31 +01:00
Anca Iordache
f2bc89a876 Merge pull request #7971 from aiordache/update_docker_setup
Bump docker-py in setup.py
2020-12-03 19:23:30 +01:00
aiordache
fee4756e33 Bump docker-py in setup.py
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-03 19:00:39 +01:00
Anca Iordache
030b347673 Merge pull request #7965 from docker/fix-project-dir
Fix project_dir to take first file in account
2020-12-03 14:21:01 +01:00
Ulysses Souza
e0edc908b5 Fix project_dir to take first file in account
The order of precedence is:
- '--project-directory' option
- first file directory in '--file' option
- current directory

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-12-02 16:59:47 -03:00
Paco Xu
6f3f696bd1 parallel_pull is default behavior in new versions (#7395)
Signed-off-by: pacoxu <paco.xu@daocloud.io>
2020-12-02 20:58:22 +01:00
lcsdtw
3f4d1ea97e docker-compose-help: improve help about down (#7411)
One could think just using `docker-compose down` already remove volumes

Signed-off-by: Dara Keon <lc.sales.duarte@gmail.com>
2020-12-02 20:56:34 +01:00
Ofek Lev
7b5be97c45 Upgrade Windows dependency (#7537)
Signed-off-by: Ofek Lev <ofekmeister@gmail.com>
2020-12-02 20:51:39 +01:00
EricsonMacedo
3e31f80977 Setup environment variables for compose. (#7490)
* Setup environment variables for compose.

- Setup environment variables to work as expected for compose
  config and context in container mode.
- Setup volume mounts based on -f, --file argument for compose
  config and context.

Signed-off-by: Ericson Macedo <macedoericson@gmail.com>

* Improve parsing of specified compose file

- Update parsing of multiple -f, --file parameters.
- Remove usage of eval command.

Signed-off-by: Ericson Macedo <macedoericson@gmail.com>
2020-12-02 20:49:54 +01:00
dependabot-preview[bot]
059fd29ec3 Bump tox from 3.19.0 to 3.20.1 (#7863)
* Bump tox from 3.19.0 to 3.20.1
* Bump tox version in Dockerfile

Bumps [tox](https://github.com/tox-dev/tox) from 3.19.0 to 3.20.1.
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/master/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/3.19.0...3.20.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-02 20:14:04 +01:00
Anca Iordache
f1059d75ed Merge pull request #7866 from luca-nardelli/improve-mandatory-variables-issues
Report which variable fails interpolation when they are mandatory
2020-12-02 20:06:25 +01:00
Anca Iordache
c45e93971f Merge pull request #7946 from aiordache/config_warning
Bring back warning for configs in non-swarm mode
2020-12-02 20:05:28 +01:00
Anca Iordache
ff42a783de Merge pull request #7889 from docker/dependabot/pip/gitpython-3.1.11
Bump gitpython from 3.1.7 to 3.1.11
2020-12-02 20:03:38 +01:00
Anca Iordache
6ec45cf2d2 Merge pull request #7902 from docker/dependabot/pip/more-itertools-8.6.0
Bump more-itertools from 8.4.0 to 8.6.0
2020-12-02 20:02:23 +01:00
dependabot-preview[bot]
4139d701f3 Bump bcrypt from 3.1.7 to 3.2.0
Bumps [bcrypt](https://github.com/pyca/bcrypt) from 3.1.7 to 3.2.0.
- [Release notes](https://github.com/pyca/bcrypt/releases)
- [Changelog](https://github.com/pyca/bcrypt/blob/master/release.py)
- [Commits](https://github.com/pyca/bcrypt/compare/3.1.7...3.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-02 19:01:24 +00:00
Anca Iordache
c56f57da12 Merge pull request #7939 from docker/dependabot/pip/virtualenv-20.2.1
Bump virtualenv from 20.0.30 to 20.2.1
2020-12-02 20:00:53 +01:00
Anca Iordache
687fa65557 Merge pull request #7917 from docker/dependabot/pip/attrs-20.3.0
Bump attrs from 20.1.0 to 20.3.0
2020-12-02 20:00:03 +01:00
Anca Iordache
5e3708e605 Merge pull request #7930 from acran/profiles
Implement service profiles
2020-12-02 19:57:19 +01:00
aiordache
d6e3af36dd Bump version in build scripts
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-02 19:54:36 +01:00
dependabot-preview[bot]
ac06e35c00 Bump attrs from 20.1.0 to 20.3.0
Bumps [attrs](https://github.com/python-attrs/attrs) from 20.1.0 to 20.3.0.
- [Release notes](https://github.com/python-attrs/attrs/releases)
- [Changelog](https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/python-attrs/attrs/compare/20.1.0...20.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-02 18:47:11 +00:00
Anca Iordache
9a913b110c Merge pull request #7952 from docker/dependabot/pip/cffi-1.14.4
Bump cffi from 1.14.1 to 1.14.4
2020-12-02 19:45:46 +01:00
dependabot-preview[bot]
929ca84db1 Bump cffi from 1.14.1 to 1.14.4
Bumps [cffi](https://github.com/python-cffi/release-doc) from 1.14.1 to 1.14.4.
- [Release notes](https://github.com/python-cffi/release-doc/releases)
- [Commits](https://github.com/python-cffi/release-doc/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-02 18:19:18 +00:00
Anca Iordache
57f8a0b039 Merge pull request #7953 from docker/dependabot/pip/cryptography-3.2.1
Bump cryptography from 3.2 to 3.2.1
2020-12-02 19:17:57 +01:00
Chris Crone
21f1d7c5e6 centos: Simplify short version variable
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-12-02 18:17:27 +00:00
Chris Crone
c87844c504 win: Bump Python version for release
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-12-02 18:16:32 +00:00
aiordache
21c07bd76c Move device requests to service_dict to avoid adding another field to config hash
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-02 18:12:39 +00:00
aiordache
8f2dbd9b12 Add devices to config hash to trigger container recreate on change
* add unit test
 * update path to compose spec schema in Makefile

Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-02 18:12:39 +00:00
aiordache
7ca88de76b Bring back warning for swarm configs
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-12-02 15:08:01 +01:00
Roman Anasal
2d2a8a0469 Implement service profiles
Implement profiles as introduced in compose-spec/compose-spec#110
fixes #7919
closes #1896
closes #6742
closes #7539

Signed-off-by: Roman Anasal <roman.anasal@bdsu.de>
2020-12-02 01:08:11 +01:00
dependabot-preview[bot]
b187f19f94 Bump cryptography from 3.2 to 3.2.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.2 to 3.2.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.2...3.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-26 18:48:15 +00:00
Anca Iordache
5c6c300ba5 Merge pull request #7944 from docker/bump-deps
Bump dependencies
2020-11-26 19:46:39 +01:00
Chris Crone
a3e6e28eeb deps: Bump Python, Docker, base images
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-11-26 15:25:09 +01:00
Anca Iordache
be8523708e Merge pull request #7872 from aiordache/use_ssh_client
Use ssh client by default
2020-11-24 13:54:48 +01:00
dependabot-preview[bot]
8785279ffd Bump virtualenv from 20.0.30 to 20.2.1
Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.0.30 to 20.2.1.
- [Release notes](https://github.com/pypa/virtualenv/releases)
- [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pypa/virtualenv/compare/20.0.30...20.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-23 22:16:04 +00:00
aiordache
e28c948f34 Shell out to ssh client for ssh connections
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-11-23 14:41:34 +01:00
aiordache
854c003359 Implement device requests for GPU support
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-11-17 13:34:58 +01:00
Mark Gallagher
3ebfa4b089 Remove duplicate values check for build.cache_from
The `docker` command accepts duplicate values, so there is no benefit to
performing this check.

Fixes #7342.

Signed-off-by: Mark Gallagher <mark@fts.scot>
2020-11-13 01:56:37 +00:00
Chris Crone
843621dfb8 Merge pull request #7906 from chris-crone/cloud-readme
Simplify README and add cloud deployment
2020-11-12 15:04:27 +01:00
Chris Crone
ea28d8edac readme: Simplify and add cloud deployment
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-11-12 13:15:23 +01:00
Anca Iordache
8633939080 Merge pull request #7796 from aiordache/update_changelog_1.27.4
Update changelog for 1.27.4 release
2020-11-12 09:35:02 +01:00
Anca Iordache
f965401569 Merge pull request #7435 from rohitkg98/7416-add-disable-log-prefix-flag
Added option to disable log prefix via cli
2020-11-12 09:34:20 +01:00
Chris Crone
bf61244f37 build: Add build for CentOS
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-11-09 18:19:02 +01:00
Chris Crone
f825cec2fc build: Refactor to use BuildKit
Signed-off-by: Chris Crone <christopher.crone@docker.com>
2020-11-09 18:19:02 +01:00
dependabot-preview[bot]
3cfccc1d64 Bump more-itertools from 8.4.0 to 8.6.0
Bumps [more-itertools](https://github.com/more-itertools/more-itertools) from 8.4.0 to 8.6.0.
- [Release notes](https://github.com/more-itertools/more-itertools/releases)
- [Commits](https://github.com/more-itertools/more-itertools/compare/v8.4.0...v8.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-11-02 22:17:02 +00:00
Ulysses Souza
675c9674e1 Add Makefile including spec download target
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-10-27 13:50:17 +01:00
dependabot-preview[bot]
df99124d72 Bump gitpython from 3.1.7 to 3.1.11
Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.7 to 3.1.11.
- [Release notes](https://github.com/gitpython-developers/GitPython/releases)
- [Changelog](https://github.com/gitpython-developers/GitPython/blob/master/CHANGES)
- [Commits](https://github.com/gitpython-developers/GitPython/compare/3.1.7...3.1.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-10-26 21:23:52 +00:00
Kaushal Rohit
cddaa77fea Added option to disable log prefix via cli
Signed-off-by: Kaushal Rohit <rohit.kg98@gmail.com>
2020-10-18 19:52:16 +05:30
Luca Nardelli
d51249acf4 Report which variable fails interpolation when they are mandatory
Add default value before raising UnsetRequiredSubstitution

Signed-off-by: Luca Nardelli <luca.nardelli@protonmail.com>
2020-10-15 09:55:04 +02:00
aiordache
062deb19c0 Update changelog for 1.27.4
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-09-25 09:49:48 +02:00
Anca Iordache
a24843e1e4 Merge pull request #7769 from aiordache/changelog_1.27.3
Update changelog for 1.27.3 release
2020-09-24 16:34:42 +02:00
aiordache
df05472bcc Remove path check for bind mounts
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-09-24 16:32:52 +02:00
Ulysses Souza
ce59a4c223 Fix port rendering
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2020-09-24 14:49:26 +02:00
Christian Höltje
1ff05ac060 run.sh: handle unix:// prefix in DOCKER_HOST
docker currently requires the `unix://` prefix when pointing `DOCKER_HOST` at a socket.

fixes #7281

Signed-off-by: Christian Höltje <docwhat@gerf.org>
2020-09-18 13:38:03 +02:00
aiordache
1192a4e817 Update changelog for 1.27.3 release
Signed-off-by: aiordache <anca.iordache@docker.com>
2020-09-17 09:47:07 +02:00
86 changed files with 8290 additions and 529 deletions

View File

@@ -7,6 +7,16 @@ assignees: ''
---
<!--
**DEPRECATION NOTICE:**
Compose V1 is end-of-life, and as such only issues relating to security vulnerabilities will be considered.
Please do not submit issues regarding bugs or improvements.
For a more up-to-date compose, check v2: https://github.com/docker/compose/tree/v2/
-->
<!--
Welcome to the docker-compose issue tracker! Before creating an issue, please heed the following:
@@ -25,7 +35,10 @@ Welcome to the docker-compose issue tracker! Before creating an issue, please he
## Context information (for bug reports)
**Output of `docker-compose version`**
- [ ] Using Compose V2 `docker compose ...`
- [ ] Using Compose V1 `docker-compose ...`
**Output of `docker(-)compose version`**
```
(paste here)
```

View File

@@ -7,6 +7,16 @@ assignees: ''
---
<!--
**DEPRECATION NOTICE:**
Compose V1 is end-of-life, and as such only issues relating to security vulnerabilities will be considered.
Please do not submit issues regarding bugs or improvements.
For a more up-to-date compose, check v2: https://github.com/docker/compose/tree/v2/
-->
<!--
Welcome to the docker-compose issue tracker! Before creating an issue, please heed the following:
@@ -19,6 +29,9 @@ Welcome to the docker-compose issue tracker! Before creating an issue, please he
the original discussion.
-->
/!\ If your request is about evolving the compose file format, please report on the [Compose Specification](https://github.com/compose-spec/compose-spec)
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

View File

@@ -7,6 +7,16 @@ assignees: ''
---
<!--
**DEPRECATION NOTICE:**
Compose V1 is end-of-life, and as such only issues relating to security vulnerabilities will be considered.
Please do not submit issues regarding bugs or improvements.
For a more up-to-date compose, check v2: https://github.com/docker/compose/tree/v2/
-->
Please post on our forums: https://forums.docker.com for questions about using `docker-compose`.
Posts that are not a bug report or a feature/enhancement request will not be addressed on this issue tracker.

28
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: weekly
time: "14:00"
timezone: America/Los_Angeles
open-pull-requests-limit: 10
ignore:
- dependency-name: python-dotenv
versions:
- 0.15.0
- 0.16.0
- dependency-name: urllib3
versions:
- 1.26.2
- 1.26.3
- dependency-name: coverage
versions:
- 5.3.1
- "5.4"
- dependency-name: packaging
versions:
- "20.8"
- dependency-name: cached-property
versions:
- 1.5.2

58
.github/workflows/artifacts.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Publish Artifacts
on:
issue_comment:
types: [created]
jobs:
publish-artifacts:
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/generate-artifacts')
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.16
uses: actions/setup-go@v2
with:
go-version: 1.16
id: go
- name: Checkout code into the Go module directory
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: Build cross platform compose-plugin binaries
run: make -f builder.Makefile cross
- name: Upload macos-amd64 binary
uses: actions/upload-artifact@v2
with:
name: docker-compose-darwin-amd64
path: ${{ github.workspace }}/bin/docker-compose-darwin-amd64
- name: Upload macos-arm64 binary
uses: actions/upload-artifact@v2
with:
name: docker-compose-darwin-arm64
path: ${{ github.workspace }}/bin/docker-compose-darwin-arm64
- name: Upload linux-amd64 binary
uses: actions/upload-artifact@v2
with:
name: docker-compose-linux-amd64
path: ${{ github.workspace }}/bin/docker-compose-linux-amd64
- name: Upload windows-amd64 binary
uses: actions/upload-artifact@v2
with:
name: docker-compose-windows-amd64.exe
path: ${{ github.workspace }}/bin/docker-compose-windows-amd64.exe
- name: Update comment
uses: peter-evans/create-or-update-comment@v1
with:
comment-id: ${{ github.event.comment.id }}
body: |
This PR can be tested using [binaries](https://github.com/docker/compose-cli/actions/runs/${{ github.run_id }}).
reactions: eyes

104
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,104 @@
name: Continuous integration
on:
push:
branches:
- v2
pull_request:
branches:
- v2
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
env:
GO111MODULE: "on"
steps:
- name: Set up Go 1.16
uses: actions/setup-go@v2
with:
go-version: 1.16
id: go
- name: Checkout code into the Go module directory
uses: actions/checkout@v2
- name: Validate go-mod is up-to-date and license headers
run: make validate
- name: Run golangci-lint
env:
BUILD_TAGS: e2e
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sudo sh -s -- -b /usr/bin/ v1.39.0
make -f builder.Makefile lint
# only on main branch, costs too much for the gain on every PR
validate-cross-build:
name: Validate cross build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
env:
GO111MODULE: "on"
steps:
- name: Set up Go 1.16
uses: actions/setup-go@v2
with:
go-version: 1.16
id: go
- name: Checkout code into the Go module directory
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
# Ensure we don't discover cross platform build issues at release time.
# Time used to build linux here is gained back in the build for local E2E step
- name: Build packages
run: make -f builder.Makefile cross
build:
name: Build
runs-on: ubuntu-latest
env:
GO111MODULE: "on"
steps:
- name: Set up Go 1.16
uses: actions/setup-go@v2
with:
go-version: 1.16
id: go
- name: Set up gosum
run: |
go get -u gotest.tools/gotestsum
- name: Setup docker CLI
run: |
curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.3.tgz | tar xz
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
- name: Checkout code into the Go module directory
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: Test
env:
BUILD_TAGS: kube
run: make -f builder.Makefile test
- name: Build for local E2E
env:
BUILD_TAGS: e2e
run: make -f builder.Makefile compose-plugin
- name: E2E Test
run: make e2e-compose

11
.github/workflows/pr-closed.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: PR cleanup
on:
pull_request:
types: [closed]
jobs:
delete_pr_artifacts:
runs-on: ubuntu-latest
steps:
- uses: stefanluptak/delete-old-pr-artifacts@v1
with:
workflow_filename: ci.yaml

19
.github/workflows/rebase.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Automatic Rebase
on:
issue_comment:
types: [created]
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

49
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: Releaser
on:
workflow_dispatch:
inputs:
tag:
description: 'Release Tag'
required: true
dry-run:
description: 'Dry run'
required: false
default: 'true'
jobs:
upload-release:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.16
uses: actions/setup-go@v2
with:
go-version: 1.16
id: go
- name: Setup docker CLI
run: |
curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.3.tgz | tar xz
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
- name: Checkout code into the Go module directory
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Build
run: make -f builder.Makefile cross-compose-plugin
- name: License
run: cp packaging/* bin/
- uses: ncipollo/release-action@v1
with:
artifacts: "bin/*"
prerelease: true
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,26 +1,28 @@
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: 'v0.9.1'
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: check-json
- id: debug-statements
- id: end-of-file-fixer
- id: flake8
- id: name-tests-test
exclude: 'tests/(integration/testcases\.py|helpers\.py)'
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: git://github.com/asottile/reorder_python_imports
sha: v1.3.4
hooks:
- id: reorder-python-imports
language_version: 'python3.7'
args:
- --py3-plus
- repo: https://github.com/asottile/pyupgrade
exclude: .github/
repos:
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: 'v0.9.1'
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: check-json
- id: debug-statements
- id: end-of-file-fixer
- id: flake8
- id: name-tests-test
exclude: 'tests/(integration/testcases\.py|helpers\.py)'
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: git://github.com/asottile/reorder_python_imports
sha: v1.3.4
hooks:
- id: reorder-python-imports
language_version: 'python3.7'
args:
- --py3-plus
- repo: https://github.com/asottile/pyupgrade
rev: v2.1.0
hooks:
- id: pyupgrade

View File

@@ -1,6 +1,229 @@
Change log
==========
1.29.2 (2021-05-10)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/59?closed=1)
### Miscellaneous
- Remove prompt to use `docker compose` in the `up` command
- Bump `py` to `1.10.0` in `requirements-indirect.txt`
1.29.1 (2021-04-13)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/58?closed=1)
### Bugs
- Fix for invalid handler warning on Windows builds
- Fix config hash to trigger container recreation on IPC mode updates
- Fix conversion map for `placement.max_replicas_per_node`
- Remove extra scan suggestion on build
1.29.0 (2021-04-06)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/56?closed=1)
### Features
- Add profile filter to `docker-compose config`
- Add a `depends_on` condition to wait for successful service completion
### Miscellaneous
- Add image scan message on build
- Update warning message for `--no-ansi` to mention `--ansi never` as alternative
- Bump docker-py to 5.0.0
- Bump PyYAML to 5.4.1
- Bump python-dotenv to 0.17.0
1.28.6 (2021-03-23)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/57?closed=1)
### Bugs
- Make `--env-file` relative to the current working directory and error out for invalid paths. Environment file paths set with `--env-file` are relative to the current working directory while the default `.env` file is located in the project directory which by default is the base directory of the Compose file.
- Fix missing service property `storage_opt` by updating the compose schema
- Fix build `extra_hosts` list format
- Remove extra error message on `exec`
### Miscellaneous
- Add `compose.yml` and `compose.yaml` to default filename list
1.28.5 (2021-02-25)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/55?closed=1)
### Bugs
- Fix OpenSSL version mismatch error when shelling out to the ssh client (via bump to docker-py 4.4.4 which contains the fix)
- Add missing build flags to the native builder: `platform`, `isolation` and `extra_hosts`
- Remove info message on native build
- Avoid fetching logs when service logging driver is set to 'none'
1.28.4 (2021-02-18)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/54?closed=1)
### Bugs
- Fix SSH port parsing by bumping docker-py to 4.4.3
### Miscellaneous
- Bump Python to 3.7.10
1.28.3 (2021-02-17)
-------------------
[List of PRs / issues for this release](https://github.com/docker/compose/milestone/53?closed=1)
### Bugs
- Fix SSH hostname parsing when it contains leading s/h, and remove the quiet option that was hiding the error (via docker-py bump to 4.4.2)
- Fix key error for '--no-log-prefix' option
- Fix incorrect CLI environment variable name for service profiles: `COMPOSE_PROFILES` instead of `COMPOSE_PROFILE`
- Fix fish completion
### Miscellaneous
- Bump cryptography to 3.3.2
- Remove log driver filter
1.28.2 (2021-01-26)
-------------------
### Miscellaneous
- CI setup update
1.28.1 (2021-01-25)
-------------------
### Bugs
- Revert to Python 3.7 bump for Linux static builds
- Add bash completion for `docker-compose logs|up --no-log-prefix`
1.28.0 (2021-01-20)
-------------------
### Features
- Support for Nvidia GPUs via device requests
- Support for service profiles
- Change the SSH connection approach to the Docker CLI's via shellout to the local SSH client (old behaviour enabled by setting `COMPOSE_PARAMIKO_SSH` environment variable)
- Add flag to disable log prefix
- Add flag for ansi output control
### Bugs
- Make `parallel_pull=True` by default
- Bring back warning for configs in non-swarm mode
- Take `--file` in account when defining `project_dir`
- On `compose up`, attach only to services we read logs from
### Miscellaneous
- Make COMPOSE_DOCKER_CLI_BUILD=1 the default
- Add usage metrics
- Sync schema with COMPOSE specification
- Improve failure report for missing mandatory environment variables
- Bump attrs to 20.3.0
- Bump more_itertools to 8.6.0
- Bump cryptograhy to 3.2.1
- Bump cffi to 1.14.4
- Bump virtualenv to 20.2.2
- Bump bcrypt to 3.2.0
- Bump gitpython to 3.1.11
- Bump docker-py to 4.4.1
- Bump Python to 3.9
- Linux: bump Debian base image from stretch to buster (required for Python 3.9)
- macOS: OpenSSL 1.1.1g to 1.1.1h, Python 3.7.7 to 3.9.0
- Bump pyinstaller 4.1
- Loosen restriction on base images to latest minor
- Updates of READMEs
1.27.4 (2020-09-24)
-------------------
### Bugs
- Remove path checks for bind mounts
- Fix port rendering to output long form syntax for non-v1
- Add protocol to the docker socket address
1.27.3 (2020-09-16)
-------------------
### Bugs
- Merge `max_replicas_per_node` on `docker-compose config`
- Fix `depends_on` serialization on `docker-compose config`
- Fix scaling when some containers are not running on `docker-compose up`
- Enable relative paths for `driver_opts.device` for `local` driver
- Allow strings for `cpus` fields
1.27.2 (2020-09-10)
-------------------

View File

@@ -1,11 +1,15 @@
ARG DOCKER_VERSION=19.03.8
ARG PYTHON_VERSION=3.7.7
ARG BUILD_ALPINE_VERSION=3.11
ARG BUILD_DEBIAN_VERSION=slim-stretch
ARG RUNTIME_ALPINE_VERSION=3.11.5
ARG RUNTIME_DEBIAN_VERSION=stretch-20200414-slim
ARG DOCKER_VERSION=19.03
ARG PYTHON_VERSION=3.7.10
ARG BUILD_PLATFORM=alpine
ARG BUILD_ALPINE_VERSION=3.12
ARG BUILD_CENTOS_VERSION=7
ARG BUILD_DEBIAN_VERSION=slim-stretch
ARG RUNTIME_ALPINE_VERSION=3.12
ARG RUNTIME_CENTOS_VERSION=7
ARG RUNTIME_DEBIAN_VERSION=stretch-slim
ARG DISTRO=alpine
FROM docker:${DOCKER_VERSION} AS docker-cli
@@ -40,32 +44,56 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
openssl \
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==20.0.30
RUN pip install tox==3.19.0
FROM centos:${BUILD_CENTOS_VERSION} AS build-centos
RUN yum install -y \
gcc \
git \
libffi-devel \
make \
openssl \
openssl-devel
WORKDIR /tmp/python3/
ARG PYTHON_VERSION
RUN curl -L https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz | tar xzf - \
&& cd Python-${PYTHON_VERSION} \
&& ./configure --enable-optimizations --enable-shared --prefix=/usr LDFLAGS="-Wl,-rpath /usr/lib" \
&& make altinstall
RUN alternatives --install /usr/bin/python python /usr/bin/python2.7 50
RUN alternatives --install /usr/bin/python python /usr/bin/python$(echo "${PYTHON_VERSION%.*}") 60
RUN curl https://bootstrap.pypa.io/get-pip.py | python -
FROM build-${DISTRO} AS build
ENTRYPOINT ["sh", "/usr/local/bin/docker-compose-entrypoint.sh"]
WORKDIR /code/
COPY docker-compose-entrypoint.sh /usr/local/bin/
COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
RUN pip install \
virtualenv==20.4.0 \
tox==3.21.2
COPY requirements-dev.txt .
COPY requirements-indirect.txt .
COPY requirements.txt .
COPY requirements-dev.txt .
RUN pip install -r requirements.txt -r requirements-indirect.txt -r requirements-dev.txt
COPY .pre-commit-config.yaml .
COPY tox.ini .
COPY setup.py .
COPY README.md .
COPY compose compose/
RUN tox --notest
RUN tox -e py37 --notest
COPY . .
ARG GIT_COMMIT=unknown
ENV DOCKER_COMPOSE_GITSHA=$GIT_COMMIT
RUN script/build/linux-entrypoint
FROM scratch AS bin
ARG TARGETARCH
ARG TARGETOS
COPY --from=build /usr/local/bin/docker-compose /docker-compose-${TARGETOS}-${TARGETARCH}
FROM alpine:${RUNTIME_ALPINE_VERSION} AS runtime-alpine
FROM debian:${RUNTIME_DEBIAN_VERSION} AS runtime-debian
FROM runtime-${BUILD_PLATFORM} AS runtime
FROM centos:${RUNTIME_CENTOS_VERSION} AS runtime-centos
FROM runtime-${DISTRO} 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

136
INSTALL.md Normal file
View File

@@ -0,0 +1,136 @@
# Install Docker Compose
This page contains information on how to install Docker Compose. You can run Compose on macOS, Windows, and 64-bit Linux.
> ⚠️ The installation instructions on this page will help you to install Compose v1 which is a deprecated version. We recommend that you use the [latest version of Docker Compose](https://docs.docker.com/compose/install/).
## Prerequisites
Docker Compose relies on Docker Engine for any meaningful work, so make sure you
have Docker Engine installed either locally or remote, depending on your setup.
- Install
[Docker Engine](https://docs.docker.com/engine/install/#server)
for your OS and then come back here for
instructions on installing the Python version of Compose.
- To run Compose as a non-root user, see [Manage Docker as a non-root user](https://docs.docker.com/engine/install/linux-postinstall/).
## Install Compose
Follow the instructions below to install Compose using the `pip`
Python package manager or to install Compose as a container.
> Install a different version
>
> The instructions below outline installation of the current stable release
> (**v1.29.2**) of Compose. To install a different version of
> Compose, replace the given release number with the one that you want. For instructions to install Compose 2.x.x on Linux, see [Install Compose 2.x.x on Linux](https://docs.docker.com/compose/install/#install-compose-on-linux-systems).
>
> Compose releases are also listed and available for direct download on the
> [Compose repository release page on GitHub](https://github.com/docker/compose/releases).
> To install a **pre-release** of Compose, refer to the [install pre-release builds](#install-pre-release-builds)
> section.
- [Install using pip](#install-using-pip)
- [Install as a container](#install-as-a-container)
#### Install using pip
> For `alpine`, the following dependency packages are needed:
> `py-pip`, `python3-dev`, `libffi-dev`, `openssl-dev`, `gcc`, `libc-dev`, `rust`, `cargo`, and `make`.
{: .important}
You can install Compose from
[pypi](https://pypi.python.org/pypi/docker-compose) using `pip`. If you install
using `pip`, we recommend that you use a
[virtualenv](https://virtualenv.pypa.io/en/latest/) because many operating
systems have python system packages that conflict with docker-compose
dependencies. See the [virtualenv
tutorial](https://docs.python-guide.org/dev/virtualenvs/) to get
started.
```console
$ pip3 install docker-compose
```
If you are not using virtualenv,
```console
$ sudo pip install docker-compose
```
> pip version 6.0 or greater is required.
#### Install as a container
You can also run Compose inside a container, from a small bash script wrapper. To
install Compose as a container run this command:
```console
$ sudo curl -L --fail https://github.com/docker/compose/releases/download/1.29.2/run.sh -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
```
### Install pre-release builds
If you're interested in trying out a pre-release build, you can download release
candidates from the [Compose repository release page on GitHub](https://github.com/docker/compose/releases).
Follow the instructions from the link, which involves running the `curl` command
in your terminal to download the binaries.
Pre-releases built from the "master" branch are also available for download at
[https://dl.bintray.com/docker-compose/master/](https://dl.bintray.com/docker-compose/master/).
> Pre-release builds allow you to try out new features before they are released,
> but may be less stable.
----
## Upgrading
If you're upgrading from Compose 1.2 or earlier, remove or
migrate your existing containers after upgrading Compose. This is because, as of
version 1.3, Compose uses Docker labels to keep track of containers, and your
containers need to be recreated to add the labels.
If Compose detects containers that were created without labels, it refuses
to run, so that you don't end up with two sets of them. If you want to keep using
your existing containers (for example, because they have data volumes you want
to preserve), you can use Compose 1.5.x to migrate them with the following
command:
```console
$ docker-compose migrate-to-labels
```
Alternatively, if you're not worried about keeping them, you can remove them.
Compose just creates new ones.
```console
$ docker container rm -f -v myapp_web_1 myapp_db_1 ...
```
## Uninstall
To uninstall Docker Compose if you installed using `curl`:
```console
$ sudo rm /usr/local/bin/docker-compose
```
To uninstall Docker Compose if you installed using `pip`:
```console
$ pip uninstall docker-compose
```
> Got a "Permission denied" error?
>
> If you get a "Permission denied" error using either of the above
> methods, you probably do not have the proper permissions to remove
> `docker-compose`. To force the removal, prepend `sudo` to either of the above
> commands and run again.

19
Jenkinsfile vendored
View File

@@ -1,6 +1,6 @@
#!groovy
def dockerVersions = ['19.03.8']
def dockerVersions = ['19.03.13']
def baseImages = ['alpine', 'debian']
def pythonVersions = ['py37']
@@ -13,6 +13,9 @@ pipeline {
timeout(time: 2, unit: 'HOURS')
timestamps()
}
environment {
DOCKER_BUILDKIT="1"
}
stages {
stage('Build test images') {
@@ -20,7 +23,7 @@ pipeline {
parallel {
stage('alpine') {
agent {
label 'ubuntu && amd64 && !zfs'
label 'ubuntu-2004 && amd64 && !zfs && cgroup1'
}
steps {
buildImage('alpine')
@@ -28,7 +31,7 @@ pipeline {
}
stage('debian') {
agent {
label 'ubuntu && amd64 && !zfs'
label 'ubuntu-2004 && amd64 && !zfs && cgroup1'
}
steps {
buildImage('debian')
@@ -59,7 +62,7 @@ pipeline {
def buildImage(baseImage) {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def imageName = "dockerpinata/compose:${baseImage}-${scmvar.GIT_COMMIT}"
image = docker.image(imageName)
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
@@ -69,7 +72,7 @@ def buildImage(baseImage) {
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--target build \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg DISTRO="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT}" \\
.\\
"""
@@ -84,9 +87,9 @@ def buildImage(baseImage) {
def runTests(dockerVersion, pythonVersion, baseImage) {
return {
stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
node("ubuntu && amd64 && !zfs") {
node("ubuntu-2004 && amd64 && !zfs && cgroup1") {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def imageName = "dockerpinata/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') {
@@ -96,6 +99,8 @@ def runTests(dockerVersion, pythonVersion, baseImage) {
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
--volume="\${DOCKER_CONFIG}/config.json:/root/.docker/config.json" \\
-e "DOCKER_TLS_CERTDIR=" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersion}" \\

57
Makefile Normal file
View File

@@ -0,0 +1,57 @@
TAG = "docker-compose:alpine-$(shell git rev-parse --short HEAD)"
GIT_VOLUME = "--volume=$(shell pwd)/.git:/code/.git"
DOCKERFILE ?="Dockerfile"
DOCKER_BUILD_TARGET ?="build"
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
BUILD_SCRIPT = linux
endif
ifeq ($(UNAME_S),Darwin)
BUILD_SCRIPT = osx
endif
COMPOSE_SPEC_SCHEMA_PATH = "compose/config/compose_spec.json"
COMPOSE_SPEC_RAW_URL = "https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json"
all: cli
cli: download-compose-spec ## Compile the cli
./script/build/$(BUILD_SCRIPT)
download-compose-spec: ## Download the compose-spec schema from it's repo
curl -so $(COMPOSE_SPEC_SCHEMA_PATH) $(COMPOSE_SPEC_RAW_URL)
cache-clear: ## Clear the builder cache
@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
base-image: ## Builds base image
docker build -f $(DOCKERFILE) -t $(TAG) --target $(DOCKER_BUILD_TARGET) .
lint: base-image ## Run linter
docker run --rm \
--tty \
$(GIT_VOLUME) \
$(TAG) \
tox -e pre-commit
test-unit: base-image ## Run tests
docker run --rm \
--tty \
$(GIT_VOLUME) \
$(TAG) \
pytest -v tests/unit/
test: ## Run all tests
./script/test/default
pre-commit: lint test-unit cli
help: ## Show help
@echo Please specify a build target. The choices are:
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
FORCE:
.PHONY: all cli download-compose-spec cache-clear base-image lint test-unit test pre-commit help

124
README.md
View File

@@ -1,62 +1,104 @@
Docker Compose
==============
[![Build Status](https://ci-next.docker.com/public/buildStatus/icon?job=compose/master)](https://ci-next.docker.com/public/job/compose/job/master/)
![Docker Compose](logo.png?raw=true "Docker Compose Logo")
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/index.md#features).
# :warning: *Compose V1 is DEPRECATED* :warning:
Since [Compose V2 is now GA](https://www.docker.com/blog/announcing-compose-v2-general-availability/), Compose V1 is officially **End of Life**. This means that:
- Active development and new features will only be added to the V2 codebase
- Only security-related issues will be considered for V1
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/index.md#common-use-cases).
Check out the [V2 branch here](https://github.com/docker/compose/tree/v2/)!!
Using Compose is basically a three-step process.
---------------------------------------------
** Compose V2 is **Generally Available**! :star_struck: **
---------------------------------------------
Check it out [here](https://github.com/docker/compose/tree/v2/)!
Read more on the [GA announcement here](https://www.docker.com/blog/announcing-compose-v2-general-availability/)
---------------------------------------------
V1 vs V2 transition :hourglass_flowing_sand:
--------------------------------------------
"Generally Available" will mean:
- New features and bug fixes will only be considered in the V2 codebase
- Users on Mac/Windows will be defaulted into Docker Compose V2, but can still opt out through the UI and the CLI. This means when running `docker-compose` you will actually be running `docker compose`
- Our current goal is for users on Linux to receive Compose v2 with the latest version of the docker CLI, but is pending some technical discussion. Users will be able to use [compose switch](https://github.com/docker/compose-switch) to enable redirection of `docker-compose` to `docker compose`
- Docker Compose V1 will continue to be maintained regarding security issues
- [v2 branch](https://github.com/docker/compose/tree/v2) will become the default one at that time
:lock_with_ink_pen: Depending on the feedback we receive from the community of GA and the adoption on Linux, we will come up with a plan to deprecate v1, but as of right now there is no concrete timeline as we want the transition to be as smooth as possible for all users. It is important to note that we have no plans of removing any aliasing of `docker-compose` to `docker compose`. We want to make it as easy as possible to switch and not break any ones scripts. We will follow up with a blog post in the next few months with more information of an exact timeline of V1 being marked as deprecated and end of support for security issues. Wed love to hear your feedback! You can provide it [here](https://github.com/docker/roadmap/issues/257).
About
-----
Docker Compose is a tool for running multi-container applications on Docker
defined using the [Compose file format](https://compose-spec.io).
A Compose file is used to define how the one or more containers that make up
your application are configured.
Once you have a Compose file, you can create and start your application with a
single command: `docker-compose up`.
Compose files can be used to deploy applications locally, or to the cloud on
[Amazon ECS](https://aws.amazon.com/ecs) or
[Microsoft ACI](https://azure.microsoft.com/services/container-instances/) using
the Docker CLI. You can read more about how to do this:
- [Compose for Amazon ECS](https://docs.docker.com/engine/context/ecs-integration/)
- [Compose for Microsoft ACI](https://docs.docker.com/engine/context/aci-integration/)
Where to get Docker Compose
----------------------------
All the instructions to install the Python version of Docker Compose, aka `v1`,
are described in the [installation guide](./INSTALL.md).
> ⚠️ This version is a deprecated version of Compose. We recommend that you use the [latest version of Docker Compose](https://docs.docker.com/compose/install/).
Quick Start
-----------
Using Docker Compose is basically a three-step process:
1. Define your app's environment with a `Dockerfile` so it can be
reproduced anywhere.
reproduced anywhere.
2. Define the services that make up your app in `docker-compose.yml` so
they can be run together in an isolated environment.
3. Lastly, run `docker-compose up` and Compose will start and run your entire app.
they can be run together in an isolated environment.
3. Lastly, run `docker-compose up` and Compose will start and run your entire
app.
A `docker-compose.yml` looks like this:
A Compose file looks like this:
version: '2'
```yaml
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: redis
```
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: redis
You can find examples of Compose applications in our
[Awesome Compose repository](https://github.com/docker/awesome-compose).
For more information about the Compose file, see the
[Compose file reference](https://github.com/docker/docker.github.io/blob/master/compose/compose-file/compose-versioning.md).
Compose has commands for managing the whole lifecycle of your application:
* Start, stop and rebuild services
* View the status of running services
* Stream the log output of running services
* Run a one-off command on a service
Installation and documentation
------------------------------
- Full documentation is available on [Docker's website](https://docs.docker.com/compose/).
- Code repository for Compose is on [GitHub](https://github.com/docker/compose).
- If you find any problems please fill out an [issue](https://github.com/docker/compose/issues/new/choose). Thank you!
For more information about the Compose format, see the
[Compose file reference](https://docs.docker.com/compose/compose-file/).
Contributing
------------
[![Build Status](https://ci-next.docker.com/public/buildStatus/icon?job=compose/master)](https://ci-next.docker.com/public/job/compose/job/master/)
Want to help develop Docker Compose? Check out our
[contributing documentation](https://github.com/docker/compose/blob/master/CONTRIBUTING.md).
Want to help build Compose? Check out our [contributing documentation](https://github.com/docker/compose/blob/master/CONTRIBUTING.md).
If you find an issue, please report it on the
[issue tracker](https://github.com/docker/compose/issues/new/choose).
Releasing
---------

View File

@@ -1,6 +1,6 @@
#!groovy
def dockerVersions = ['19.03.8', '18.09.9']
def dockerVersions = ['19.03.13', '18.09.9']
def baseImages = ['alpine', 'debian']
def pythonVersions = ['py37']
@@ -13,6 +13,9 @@ pipeline {
timeout(time: 2, unit: 'HOURS')
timestamps()
}
environment {
DOCKER_BUILDKIT="1"
}
stages {
stage('Build test images') {
@@ -20,7 +23,7 @@ pipeline {
parallel {
stage('alpine') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildImage('alpine')
@@ -28,7 +31,7 @@ pipeline {
}
stage('debian') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildImage('debian')
@@ -38,7 +41,7 @@ pipeline {
}
stage('Test') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
// TODO use declarative 1.5.0 `matrix` once available on CI
@@ -58,7 +61,7 @@ pipeline {
}
stage('Generate Changelog') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
checkout scm
@@ -81,7 +84,7 @@ pipeline {
steps {
checkout scm
sh './script/setup/osx'
sh 'tox -e py37 -- tests/unit'
sh 'tox -e py39 -- tests/unit'
sh './script/build/osx'
dir ('dist') {
checksum('docker-compose-Darwin-x86_64')
@@ -95,7 +98,7 @@ pipeline {
}
stage('linux binary') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
checkout scm
@@ -114,11 +117,11 @@ pipeline {
label 'windows-python'
}
environment {
PATH = "$PATH;C:\\Python37;C:\\Python37\\Scripts"
PATH = "C:\\Python39;C:\\Python39\\Scripts;$PATH"
}
steps {
checkout scm
bat 'tox.exe -e py37 -- tests/unit'
bat 'tox.exe -e py39 -- tests/unit'
powershell '.\\script\\build\\windows.ps1'
dir ('dist') {
checksum('docker-compose-Windows-x86_64.exe')
@@ -131,7 +134,7 @@ pipeline {
}
stage('alpine image') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildRuntimeImage('alpine')
@@ -139,7 +142,7 @@ pipeline {
}
stage('debian image') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildRuntimeImage('debian')
@@ -154,7 +157,7 @@ pipeline {
parallel {
stage('Pushing images') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
pushRuntimeImage('alpine')
@@ -163,7 +166,7 @@ pipeline {
}
stage('Creating Github Release') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
environment {
GITHUB_TOKEN = credentials('github-release-token')
@@ -195,7 +198,7 @@ pipeline {
}
stage('Publishing Python packages') {
agent {
label 'linux && docker && ubuntu-2004'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
environment {
PYPIRC = credentials('pypirc-docker-dsg-cibot')
@@ -219,7 +222,7 @@ pipeline {
def buildImage(baseImage) {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def imageName = "dockerpinata/compose:${baseImage}-${scmvar.GIT_COMMIT}"
image = docker.image(imageName)
withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
@@ -229,7 +232,7 @@ def buildImage(baseImage) {
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--target build \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg DISTRO="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT}" \\
.\\
"""
@@ -244,9 +247,9 @@ def buildImage(baseImage) {
def runTests(dockerVersion, pythonVersion, baseImage) {
return {
stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
node("linux && docker && ubuntu-2004") {
node("linux && docker && ubuntu-2004 && amd64 && cgroup1") {
def scmvar = checkout(scm)
def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def imageName = "dockerpinata/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') {
@@ -256,6 +259,8 @@ def runTests(dockerVersion, pythonVersion, baseImage) {
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
--volume="\${DOCKER_CONFIG}/config.json:/root/.docker/config.json" \\
-e "DOCKER_TLS_CERTDIR=" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersion}" \\
@@ -276,7 +281,7 @@ def buildRuntimeImage(baseImage) {
def imageName = "docker/compose:${baseImage}-${env.BRANCH_NAME}"
ansiColor('xterm') {
sh """docker build -t ${imageName} \\
--build-arg BUILD_PLATFORM="${baseImage}" \\
--build-arg DISTRO="${baseImage}" \\
--build-arg GIT_COMMIT="${scmvar.GIT_COMMIT.take(7)}" \\
.
"""

View File

@@ -1 +1 @@
__version__ = '1.28.0dev'
__version__ = '1.30.0dev'

View File

@@ -1,3 +1,6 @@
import enum
import os
from ..const import IS_WINDOWS_PLATFORM
NAMES = [
@@ -12,6 +15,21 @@ NAMES = [
]
@enum.unique
class AnsiMode(enum.Enum):
"""Enumeration for when to output ANSI colors."""
NEVER = "never"
ALWAYS = "always"
AUTO = "auto"
def use_ansi_codes(self, stream):
if self is AnsiMode.ALWAYS:
return True
if self is AnsiMode.NEVER or os.environ.get('CLICOLOR') == '0':
return False
return stream.isatty()
def get_pairs():
for i, name in enumerate(NAMES):
yield (name, str(30 + i))

View File

@@ -35,7 +35,7 @@ SILENT_COMMANDS = {
def project_from_options(project_dir, options, additional_options=None):
additional_options = additional_options or {}
override_dir = options.get('--project-directory')
override_dir = get_project_dir(options)
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
@@ -59,14 +59,15 @@ def project_from_options(project_dir, options, additional_options=None):
return get_project(
project_dir,
get_config_path_from_options(project_dir, options, environment),
get_config_path_from_options(options, environment),
project_name=options.get('--project-name'),
verbose=options.get('--verbose'),
context=context,
environment=environment,
override_dir=override_dir,
interpolate=(not additional_options.get('--no-interpolate')),
environment_file=environment_file
environment_file=environment_file,
enabled_profiles=get_profiles_from_options(options, environment)
)
@@ -86,21 +87,29 @@ def set_parallel_limit(environment):
parallel.GlobalLimit.set_global_limit(parallel_limit)
def get_project_dir(options):
override_dir = None
files = get_config_path_from_options(options, os.environ)
if files:
if files[0] == '-':
return '.'
override_dir = os.path.dirname(files[0])
return options.get('--project-directory') or override_dir
def get_config_from_options(base_dir, options, additional_options=None):
additional_options = additional_options or {}
override_dir = options.get('--project-directory')
override_dir = get_project_dir(options)
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
)
config_path = get_config_path_from_options(options, environment)
return config.load(
config.find(base_dir, config_path, environment, override_dir),
not additional_options.get('--no-interpolate')
)
def get_config_path_from_options(base_dir, options, environment):
def get_config_path_from_options(options, environment):
def unicode_paths(paths):
return [p.decode('utf-8') if isinstance(p, bytes) else p for p in paths]
@@ -115,9 +124,21 @@ def get_config_path_from_options(base_dir, options, environment):
return None
def get_profiles_from_options(options, environment):
profile_option = options.get('--profile')
if profile_option:
return profile_option
profiles = environment.get('COMPOSE_PROFILES')
if profiles:
return profiles.split(',')
return []
def get_project(project_dir, config_path=None, project_name=None, verbose=False,
context=None, environment=None, override_dir=None,
interpolate=True, environment_file=None):
interpolate=True, environment_file=None, enabled_profiles=None):
if not environment:
environment = Environment.from_env_file(project_dir)
config_details = config.find(project_dir, config_path, environment, override_dir)
@@ -139,6 +160,7 @@ def get_project(project_dir, config_path=None, project_name=None, verbose=False,
client,
environment.get('DOCKER_DEFAULT_PLATFORM'),
execution_context_labels(config_details, environment_file),
enabled_profiles,
)

View File

@@ -166,8 +166,8 @@ def docker_client(environment, version=None, context=None, tls_version=None):
kwargs['credstore_env'] = {
'LD_LIBRARY_PATH': environment.get('LD_LIBRARY_PATH_ORIG'),
}
client = APIClient(**kwargs)
use_paramiko_ssh = int(environment.get('COMPOSE_PARAMIKO_SSH', 0))
client = APIClient(use_ssh_client=not use_paramiko_ssh, **kwargs)
client._original_base_url = kwargs.get('base_url')
return client

View File

@@ -17,10 +17,16 @@ class DocoptDispatcher:
self.command_class = command_class
self.options = options
@classmethod
def get_command_and_options(cls, doc_entity, argv, options):
command_help = getdoc(doc_entity)
opt = docopt_full_help(command_help, argv, **options)
command = opt['COMMAND']
return command_help, opt, command
def parse(self, argv):
command_help = getdoc(self.command_class)
options = docopt_full_help(command_help, argv, **self.options)
command = options['COMMAND']
command_help, options, command = DocoptDispatcher.get_command_and_options(
self.command_class, argv, self.options)
if command is None:
raise SystemExit(command_help)

View File

@@ -16,18 +16,22 @@ from compose.utils import split_buffer
class LogPresenter:
def __init__(self, prefix_width, color_func):
def __init__(self, prefix_width, color_func, keep_prefix=True):
self.prefix_width = prefix_width
self.color_func = color_func
self.keep_prefix = keep_prefix
def present(self, container, line):
prefix = container.name_without_project.ljust(self.prefix_width)
return '{prefix} {line}'.format(
prefix=self.color_func(prefix + ' |'),
line=line)
to_log = '{line}'.format(line=line)
if self.keep_prefix:
prefix = container.name_without_project.ljust(self.prefix_width)
to_log = '{prefix} '.format(prefix=self.color_func(prefix + ' |')) + to_log
return to_log
def build_log_presenters(service_names, monochrome):
def build_log_presenters(service_names, monochrome, keep_prefix=True):
"""Return an iterable of functions.
Each function can be used to format the logs output of a container.
@@ -38,7 +42,7 @@ def build_log_presenters(service_names, monochrome):
return text
for color_func in cycle([no_color] if monochrome else colors.rainbow()):
yield LogPresenter(prefix_width, color_func)
yield LogPresenter(prefix_width, color_func, keep_prefix)
def max_name_width(service_names, max_index_width=3):
@@ -154,10 +158,8 @@ class QueueItem(namedtuple('_QueueItem', 'item is_stop exc')):
def tail_container_logs(container, presenter, queue, log_args):
generator = get_log_generator(container)
try:
for item in generator(container, log_args):
for item in build_log_generator(container, log_args):
queue.put(QueueItem.new(presenter.present(container, item)))
except Exception as e:
queue.put(QueueItem.exception(e))
@@ -167,20 +169,6 @@ def tail_container_logs(container, presenter, queue, log_args):
queue.put(QueueItem.stop(container.name))
def get_log_generator(container):
if container.has_api_logs:
return build_log_generator
return build_no_log_generator
def build_no_log_generator(container, log_args):
"""Return a generator that prints a warning about logs and waits for
container to exit.
"""
yield "WARNING: no logs are available with the '{}' log driver\n".format(
container.log_driver)
def build_log_generator(container, log_args):
# if the container doesn't have a log_stream we need to attach to container
# before log printer starts running

View File

@@ -2,7 +2,6 @@ import contextlib
import functools
import json
import logging
import os
import pipes
import re
import subprocess
@@ -24,8 +23,11 @@ from ..config import resolve_build_args
from ..config.environment import Environment
from ..config.serialize import serialize_config
from ..config.types import VolumeSpec
from ..const import IS_LINUX_PLATFORM
from ..const import IS_WINDOWS_PLATFORM
from ..errors import StreamParseError
from ..metrics.decorator import metrics
from ..parallel import ParallelStreamWriter
from ..progress_stream import StreamOutputError
from ..project import get_image_digests
from ..project import MissingDigests
@@ -38,7 +40,10 @@ from ..service import ConvergenceStrategy
from ..service import ImageType
from ..service import NeedsBuildError
from ..service import OperationFailedError
from ..utils import filter_attached_for_up
from .colors import AnsiMode
from .command import get_config_from_options
from .command import get_project_dir
from .command import project_from_options
from .docopt_command import DocoptDispatcher
from .docopt_command import get_handler
@@ -51,60 +56,132 @@ from .log_printer import LogPrinter
from .utils import get_version_info
from .utils import human_readable_file_size
from .utils import yesno
from compose.metrics.client import MetricsCommand
from compose.metrics.client import Status
if not IS_WINDOWS_PLATFORM:
from dockerpty.pty import PseudoTerminal, RunOperation, ExecOperation
log = logging.getLogger(__name__)
console_handler = logging.StreamHandler(sys.stderr)
def main():
def main(): # noqa: C901
signals.ignore_sigpipe()
command = None
try:
command = dispatch()
command()
_, opts, command = DocoptDispatcher.get_command_and_options(
TopLevelCommand,
get_filtered_args(sys.argv[1:]),
{'options_first': True, 'version': get_version_info('compose')})
except Exception:
pass
try:
command_func = dispatch()
command_func()
if not IS_LINUX_PLATFORM and command == 'help':
print("\nDocker Compose is now in the Docker CLI, try `docker compose` help")
except (KeyboardInterrupt, signals.ShutdownException):
log.error("Aborting.")
sys.exit(1)
exit_with_metrics(command, "Aborting.", status=Status.CANCELED)
except (UserError, NoSuchService, ConfigurationError,
ProjectError, OperationFailedError) as e:
log.error(e.msg)
sys.exit(1)
exit_with_metrics(command, e.msg, status=Status.FAILURE)
except BuildError as e:
reason = ""
if e.reason:
reason = " : " + e.reason
log.error("Service '{}' failed to build{}".format(e.service.name, reason))
sys.exit(1)
exit_with_metrics(command,
"Service '{}' failed to build{}".format(e.service.name, reason),
status=Status.FAILURE)
except StreamOutputError as e:
log.error(e)
sys.exit(1)
exit_with_metrics(command, e, status=Status.FAILURE)
except NeedsBuildError as e:
log.error("Service '{}' needs to be built, but --no-build was passed.".format(e.service.name))
sys.exit(1)
exit_with_metrics(command,
"Service '{}' needs to be built, but --no-build was passed.".format(
e.service.name), status=Status.FAILURE)
except NoSuchCommand as e:
commands = "\n".join(parse_doc_section("commands:", getdoc(e.supercommand)))
log.error("No such command: %s\n\n%s", e.command, commands)
sys.exit(1)
if not IS_LINUX_PLATFORM:
commands += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`"
exit_with_metrics("", log_msg="No such command: {}\n\n{}".format(
e.command, commands), status=Status.FAILURE)
except (errors.ConnectionError, StreamParseError):
sys.exit(1)
exit_with_metrics(command, status=Status.FAILURE)
except SystemExit as e:
status = Status.SUCCESS
if len(sys.argv) > 1 and '--help' not in sys.argv:
status = Status.FAILURE
if command and len(sys.argv) >= 3 and sys.argv[2] == '--help':
command = '--help ' + command
if not command and len(sys.argv) >= 2 and sys.argv[1] == '--help':
command = '--help'
msg = e.args[0] if len(e.args) else ""
code = 0
if isinstance(e.code, int):
code = e.code
if not IS_LINUX_PLATFORM and not command:
msg += "\n\nDocker Compose is now in the Docker CLI, try `docker compose`"
exit_with_metrics(command, log_msg=msg, status=status,
exit_code=code)
def get_filtered_args(args):
if args[0] in ('-h', '--help'):
return []
if args[0] == '--version':
return ['version']
def exit_with_metrics(command, log_msg=None, status=Status.SUCCESS, exit_code=1):
if log_msg and command != 'exec':
if not exit_code:
log.info(log_msg)
else:
log.error(log_msg)
MetricsCommand(command, status=status).send_metrics()
sys.exit(exit_code)
def dispatch():
setup_logging()
console_stream = sys.stderr
console_handler = logging.StreamHandler(console_stream)
setup_logging(console_handler)
dispatcher = DocoptDispatcher(
TopLevelCommand,
{'options_first': True, 'version': get_version_info('compose')})
options, handler, command_options = dispatcher.parse(sys.argv[1:])
ansi_mode = AnsiMode.AUTO
try:
if options.get("--ansi"):
ansi_mode = AnsiMode(options.get("--ansi"))
except ValueError:
raise UserError(
'Invalid value for --ansi: {}. Expected one of {}.'.format(
options.get("--ansi"),
', '.join(m.value for m in AnsiMode)
)
)
if options.get("--no-ansi"):
if options.get("--ansi"):
raise UserError("--no-ansi and --ansi cannot be combined.")
log.warning('--no-ansi option is deprecated and will be removed in future versions. '
'Use `--ansi never` instead.')
ansi_mode = AnsiMode.NEVER
setup_console_handler(console_handler,
options.get('--verbose'),
set_no_color_if_clicolor(options.get('--no-ansi')),
ansi_mode.use_ansi_codes(console_handler.stream),
options.get("--log-level"))
setup_parallel_logger(set_no_color_if_clicolor(options.get('--no-ansi')))
if options.get('--no-ansi'):
setup_parallel_logger(ansi_mode)
if ansi_mode is AnsiMode.NEVER:
command_options['--no-color'] = True
return functools.partial(perform_command, options, handler, command_options)
@@ -126,23 +203,23 @@ def perform_command(options, handler, command_options):
handler(command, command_options)
def setup_logging():
def setup_logging(console_handler):
root_logger = logging.getLogger()
root_logger.addHandler(console_handler)
root_logger.setLevel(logging.DEBUG)
# Disable requests logging
# Disable requests and docker-py logging
logging.getLogger("urllib3").propagate = False
logging.getLogger("requests").propagate = False
logging.getLogger("docker").propagate = False
def setup_parallel_logger(noansi):
if noansi:
import compose.parallel
compose.parallel.ParallelStreamWriter.set_noansi()
def setup_parallel_logger(ansi_mode):
ParallelStreamWriter.set_default_ansi_mode(ansi_mode)
def setup_console_handler(handler, verbose, noansi=False, level=None):
if handler.stream.isatty() and noansi is False:
def setup_console_handler(handler, verbose, use_console_formatter=True, level=None):
if use_console_formatter:
format_class = ConsoleWarningFormatter
else:
format_class = logging.Formatter
@@ -182,7 +259,7 @@ class TopLevelCommand:
"""Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [--] [COMMAND] [ARGS...]
docker-compose [-f <arg>...] [--profile <name>...] [options] [--] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
@@ -190,10 +267,12 @@ class TopLevelCommand:
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
--profile NAME Specify a profile to enable
-c, --context NAME Specify a context name
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi Do not print ANSI control characters
--ansi (never|always|auto) Control when to print ANSI control characters
--no-ansi Do not print ANSI control characters (DEPRECATED)
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
@@ -214,7 +293,7 @@ class TopLevelCommand:
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
down Stop and remove resources
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
@@ -244,13 +323,14 @@ class TopLevelCommand:
@property
def project_dir(self):
return self.toplevel_options.get('--project-directory') or '.'
return get_project_dir(self.toplevel_options)
@property
def toplevel_environment(self):
environment_file = self.toplevel_options.get('--env-file')
return Environment.from_env_file(self.project_dir, environment_file)
@metrics()
def build(self, options):
"""
Build or rebuild services.
@@ -270,8 +350,6 @@ class TopLevelCommand:
--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
"""
@@ -285,7 +363,7 @@ class TopLevelCommand:
)
build_args = resolve_build_args(build_args, self.toplevel_environment)
native_builder = self.toplevel_environment.get_boolean('COMPOSE_DOCKER_CLI_BUILD')
native_builder = self.toplevel_environment.get_boolean('COMPOSE_DOCKER_CLI_BUILD', True)
self.project.build(
service_names=options['SERVICE'],
@@ -302,6 +380,7 @@ class TopLevelCommand:
progress=options.get('--progress'),
)
@metrics()
def config(self, options):
"""
Validate and view the Compose file.
@@ -313,6 +392,7 @@ class TopLevelCommand:
--no-interpolate Don't interpolate environment variables.
-q, --quiet Only validate the configuration, don't print
anything.
--profiles Print the profile names, one per line.
--services Print the service names, one per line.
--volumes Print the volume names, one per line.
--hash="*" Print the service config hash, one per line.
@@ -332,6 +412,15 @@ class TopLevelCommand:
if options['--quiet']:
return
if options['--profiles']:
profiles = set()
for service in compose_config.services:
if 'profiles' in service:
for profile in service['profiles']:
profiles.add(profile)
print('\n'.join(sorted(profiles)))
return
if options['--services']:
print('\n'.join(service['name'] for service in compose_config.services))
return
@@ -351,6 +440,7 @@ class TopLevelCommand:
print(serialize_config(compose_config, image_digests, not options['--no-interpolate']))
@metrics()
def create(self, options):
"""
Creates containers for a service.
@@ -379,6 +469,7 @@ class TopLevelCommand:
do_build=build_action_from_opts(options),
)
@metrics()
def down(self, options):
"""
Stops containers and removes containers, networks, volumes, and images
@@ -430,6 +521,7 @@ class TopLevelCommand:
Options:
--json Output events as a stream of json objects
"""
def format_event(event):
attributes = ["%s=%s" % item for item in event['attributes'].items()]
return ("{time} {type} {action} {id} ({attrs})").format(
@@ -446,6 +538,7 @@ class TopLevelCommand:
print(formatter(event))
sys.stdout.flush()
@metrics("exec")
def exec_command(self, options):
"""
Execute a command in a running container
@@ -522,6 +615,7 @@ class TopLevelCommand:
sys.exit(exit_code)
@classmethod
@metrics()
def help(cls, options):
"""
Get help on a command.
@@ -535,6 +629,7 @@ class TopLevelCommand:
print(getdoc(subject))
@metrics()
def images(self, options):
"""
List images used by the created containers.
@@ -589,6 +684,7 @@ class TopLevelCommand:
])
print(Formatter.table(headers, rows))
@metrics()
def kill(self, options):
"""
Force stop service containers.
@@ -603,6 +699,7 @@ class TopLevelCommand:
self.project.kill(service_names=options['SERVICE'], signal=signal)
@metrics()
def logs(self, options):
"""
View output from containers.
@@ -610,11 +707,12 @@ class TopLevelCommand:
Usage: logs [options] [--] [SERVICE...]
Options:
--no-color Produce monochrome output.
-f, --follow Follow log output.
-t, --timestamps Show timestamps.
--tail="all" Number of lines to show from the end of the logs
for each container.
--no-color Produce monochrome output.
-f, --follow Follow log output.
-t, --timestamps Show timestamps.
--tail="all" Number of lines to show from the end of the logs
for each container.
--no-log-prefix Don't print prefix in logs.
"""
containers = self.project.containers(service_names=options['SERVICE'], stopped=True)
@@ -633,10 +731,12 @@ class TopLevelCommand:
log_printer_from_project(
self.project,
containers,
set_no_color_if_clicolor(options['--no-color']),
options['--no-color'],
log_args,
event_stream=self.project.events(service_names=options['SERVICE'])).run()
event_stream=self.project.events(service_names=options['SERVICE']),
keep_prefix=not options['--no-log-prefix']).run()
@metrics()
def pause(self, options):
"""
Pause services.
@@ -646,6 +746,7 @@ class TopLevelCommand:
containers = self.project.pause(service_names=options['SERVICE'])
exit_if(not containers, 'No containers to pause', 1)
@metrics()
def port(self, options):
"""
Print the public port for a port binding.
@@ -667,6 +768,7 @@ class TopLevelCommand:
options['PRIVATE_PORT'],
protocol=options.get('--protocol') or 'tcp') or '')
@metrics()
def ps(self, options):
"""
List containers.
@@ -676,7 +778,9 @@ class TopLevelCommand:
Options:
-q, --quiet Only display IDs
--services Display services
--filter KEY=VAL Filter services by a property
--filter KEY=VAL Filter services by a property. KEY is either:
1. `source` with values `image`, or `build`;
2. `status` with values `running`, `stopped`, `paused`, or `restarted`.
-a, --all Show all stopped containers (including those created by the run command)
"""
if options['--quiet'] and options['--services']:
@@ -723,6 +827,7 @@ class TopLevelCommand:
])
print(Formatter.table(headers, rows))
@metrics()
def pull(self, options):
"""
Pulls images for services defined in a Compose file, but does not start the containers.
@@ -746,6 +851,7 @@ class TopLevelCommand:
include_deps=options.get('--include-deps'),
)
@metrics()
def push(self, options):
"""
Pushes images for services.
@@ -760,6 +866,7 @@ class TopLevelCommand:
ignore_push_failures=options.get('--ignore-push-failures')
)
@metrics()
def rm(self, options):
"""
Removes stopped service containers.
@@ -804,6 +911,7 @@ class TopLevelCommand:
else:
print("No stopped containers")
@metrics()
def run(self, options):
"""
Run a one-off command on a service.
@@ -864,6 +972,7 @@ class TopLevelCommand:
self.toplevel_options, self.toplevel_environment
)
@metrics()
def scale(self, options):
"""
Set number of containers to run for a service.
@@ -892,6 +1001,7 @@ class TopLevelCommand:
for service_name, num in parse_scale_args(options['SERVICE=NUM']).items():
self.project.get_service(service_name).scale(num, timeout=timeout)
@metrics()
def start(self, options):
"""
Start existing containers.
@@ -901,6 +1011,7 @@ class TopLevelCommand:
containers = self.project.start(service_names=options['SERVICE'])
exit_if(not containers, 'No containers to start', 1)
@metrics()
def stop(self, options):
"""
Stop running containers without removing them.
@@ -916,6 +1027,7 @@ class TopLevelCommand:
timeout = timeout_from_opts(options)
self.project.stop(service_names=options['SERVICE'], timeout=timeout)
@metrics()
def restart(self, options):
"""
Restart running containers.
@@ -930,6 +1042,7 @@ class TopLevelCommand:
containers = self.project.restart(service_names=options['SERVICE'], timeout=timeout)
exit_if(not containers, 'No containers to restart', 1)
@metrics()
def top(self, options):
"""
Display the running processes
@@ -957,6 +1070,7 @@ class TopLevelCommand:
print(container.name)
print(Formatter.table(headers, rows))
@metrics()
def unpause(self, options):
"""
Unpause services.
@@ -966,6 +1080,7 @@ class TopLevelCommand:
containers = self.project.unpause(service_names=options['SERVICE'])
exit_if(not containers, 'No containers to unpause', 1)
@metrics()
def up(self, options):
"""
Builds, (re)creates, starts, and attaches to containers for a service.
@@ -1017,6 +1132,7 @@ class TopLevelCommand:
container. Implies --abort-on-container-exit.
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.
--no-log-prefix Don't print prefix in logs.
"""
start_deps = not options['--no-deps']
always_recreate_deps = options['--always-recreate-deps']
@@ -1028,6 +1144,7 @@ class TopLevelCommand:
detached = options.get('--detach')
no_start = options.get('--no-start')
attach_dependencies = options.get('--attach-dependencies')
keep_prefix = not options.get('--no-log-prefix')
if detached and (cascade_stop or exit_value_from or attach_dependencies):
raise UserError(
@@ -1042,7 +1159,7 @@ class TopLevelCommand:
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')
native_builder = self.toplevel_environment.get_boolean('COMPOSE_DOCKER_CLI_BUILD', True)
with up_shutdown_context(self.project, service_names, timeout, detached):
warn_for_swarm_mode(self.project.client)
@@ -1064,6 +1181,7 @@ class TopLevelCommand:
renew_anonymous_volumes=options.get('--renew-anon-volumes'),
silent=options.get('--quiet-pull'),
cli=native_builder,
attach_dependencies=attach_dependencies,
)
try:
@@ -1091,10 +1209,11 @@ class TopLevelCommand:
log_printer = log_printer_from_project(
self.project,
attached_containers,
set_no_color_if_clicolor(options['--no-color']),
options['--no-color'],
{'follow': True},
cascade_stop,
event_stream=self.project.events(service_names=service_names))
event_stream=self.project.events(service_names=service_names),
keep_prefix=keep_prefix)
print("Attaching to", list_containers(log_printer.containers))
cascade_starter = log_printer.run()
@@ -1112,6 +1231,7 @@ class TopLevelCommand:
sys.exit(exit_code)
@classmethod
@metrics()
def version(cls, options):
"""
Show version information and quit.
@@ -1376,29 +1496,28 @@ def get_docker_start_call(container_options, container_id):
def log_printer_from_project(
project,
containers,
monochrome,
log_args,
cascade_stop=False,
event_stream=None,
project,
containers,
monochrome,
log_args,
cascade_stop=False,
event_stream=None,
keep_prefix=True,
):
return LogPrinter(
containers,
build_log_presenters(project.service_names, monochrome),
[c for c in containers if c.log_driver not in (None, 'none')],
build_log_presenters(project.service_names, monochrome, keep_prefix),
event_stream or project.events(),
cascade_stop=cascade_stop,
log_args=log_args)
def filter_attached_containers(containers, service_names, attach_dependencies=False):
if attach_dependencies or not service_names:
return containers
return [
container
for container in containers if container.service in service_names
]
return filter_attached_for_up(
containers,
service_names,
attach_dependencies,
lambda container: container.service)
@contextlib.contextmanager
@@ -1574,7 +1693,3 @@ def warn_for_swarm_mode(client):
"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

@@ -1,14 +1,16 @@
{
"$schema": "http://json-schema.org/draft/2019-09/schema#",
"id": "config_schema_compose_spec.json",
"id": "compose_spec.json",
"type": "object",
"title": "Compose Specification",
"description": "The Compose file is a YAML file defining a multi-containers based application.",
"properties": {
"version": {
"type": "string",
"description": "Version of the Compose specification used. Tools not implementing required version MUST reject the configuration file."
},
"services": {
"id": "#/properties/services",
"type": "object",
@@ -19,6 +21,7 @@
},
"additionalProperties": false
},
"networks": {
"id": "#/properties/networks",
"type": "object",
@@ -28,6 +31,7 @@
}
}
},
"volumes": {
"id": "#/properties/volumes",
"type": "object",
@@ -38,6 +42,7 @@
},
"additionalProperties": false
},
"secrets": {
"id": "#/properties/secrets",
"type": "object",
@@ -48,6 +53,7 @@
},
"additionalProperties": false
},
"configs": {
"id": "#/properties/configs",
"type": "object",
@@ -59,12 +65,16 @@
"additionalProperties": false
}
},
"patternProperties": {"^x-": {}},
"additionalProperties": false,
"definitions": {
"service": {
"id": "#/definitions/service",
"type": "object",
"properties": {
"deploy": {"$ref": "#/definitions/deployment"},
"build": {
@@ -77,7 +87,7 @@
"dockerfile": {"type": "string"},
"args": {"$ref": "#/definitions/list_or_dict"},
"labels": {"$ref": "#/definitions/list_or_dict"},
"cache_from": {"$ref": "#/definitions/list_of_strings"},
"cache_from": {"type": "array", "items": {"type": "string"}},
"network": {"type": "string"},
"target": {"type": "string"},
"shm_size": {"type": ["integer", "string"]},
@@ -178,7 +188,7 @@
"properties": {
"condition": {
"type": "string",
"enum": ["service_started", "service_healthy"]
"enum": ["service_started", "service_healthy", "service_completed_successfully"]
}
},
"required": ["condition"]
@@ -190,7 +200,6 @@
"device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"},
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"dns": {"$ref": "#/definitions/string_or_list"},
"dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true},
"dns_search": {"$ref": "#/definitions/string_or_list"},
"domainname": {"type": "string"},
@@ -211,12 +220,12 @@
},
"uniqueItems": true
},
"extends": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"service": {"type": "string"},
"file": {"type": "string"}
@@ -245,6 +254,7 @@
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"logging": {
"type": "object",
"properties": {
"driver": {"type": "string"},
"options": {
@@ -258,7 +268,7 @@
"patternProperties": {"^x-": {}}
},
"mac_address": {"type": "string"},
"mem_limit": {"type": "string"},
"mem_limit": {"type": ["number", "string"]},
"mem_reservation": {"type": ["string", "integer"]},
"mem_swappiness": {"type": "integer"},
"memswap_limit": {"type": ["number", "string"]},
@@ -318,13 +328,13 @@
"uniqueItems": true
},
"privileged": {"type": "boolean"},
"profiles": {"$ref": "#/definitions/list_of_strings"},
"pull_policy": {"type": "string", "enum": [
"always", "never", "if_not_present"
"always", "never", "if_not_present", "build"
]},
"read_only": {"type": "boolean"},
"restart": {"type": "string"},
"runtime": {
"deprecated": true,
"type": "string"
},
"scale": {
@@ -356,6 +366,7 @@
"stdin_open": {"type": "boolean"},
"stop_grace_period": {"type": "string", "format": "duration"},
"stop_signal": {"type": "string"},
"storage_opt": {"type": "object"},
"tmpfs": {"$ref": "#/definitions/string_or_list"},
"tty": {"type": "boolean"},
"ulimits": {
@@ -425,9 +436,9 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
}
],
"uniqueItems": true
}
]
},
"uniqueItems": true
},
"volumes_from": {
"type": "array",
@@ -514,7 +525,8 @@
"properties": {
"cpus": {"type": ["number", "string"]},
"memory": {"type": "string"},
"generic_resources": {"$ref": "#/definitions/generic_resources"}
"generic_resources": {"$ref": "#/definitions/generic_resources"},
"devices": {"$ref": "#/definitions/devices"}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
@@ -558,6 +570,7 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"generic_resources": {
"id": "#/definitions/generic_resources",
"type": "array",
@@ -578,6 +591,24 @@
"patternProperties": {"^x-": {}}
}
},
"devices": {
"id": "#/definitions/devices",
"type": "array",
"items": {
"type": "object",
"properties": {
"capabilities": {"$ref": "#/definitions/list_of_strings"},
"count": {"type": ["string", "integer"]},
"device_ids": {"$ref": "#/definitions/list_of_strings"},
"driver":{"type": "string"},
"options":{"$ref": "#/definitions/list_or_dict"}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
}
},
"network": {
"id": "#/definitions/network",
"type": ["object", "null"],
@@ -607,10 +638,10 @@
"additionalProperties": false,
"patternProperties": {"^.+$": {"type": "string"}}
}
}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
}
},
"options": {
"type": "object",
@@ -640,6 +671,7 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"volume": {
"id": "#/definitions/volume",
"type": ["object", "null"],
@@ -668,6 +700,7 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"secret": {
"id": "#/definitions/secret",
"type": "object",
@@ -693,6 +726,7 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"config": {
"id": "#/definitions/config",
"type": "object",
@@ -714,17 +748,20 @@
"additionalProperties": false,
"patternProperties": {"^x-": {}}
},
"string_or_list": {
"oneOf": [
{"type": "string"},
{"$ref": "#/definitions/list_of_strings"}
]
},
"list_of_strings": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": true
},
"list_or_dict": {
"oneOf": [
{
@@ -739,6 +776,7 @@
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
]
},
"blkio_limit": {
"type": "object",
"properties": {
@@ -755,6 +793,7 @@
},
"additionalProperties": false
},
"constraints": {
"service": {
"id": "#/definitions/constraints/service",

View File

@@ -10,7 +10,11 @@ from operator import attrgetter
from operator import itemgetter
import yaml
from cached_property import cached_property
try:
from functools import cached_property
except ImportError:
from cached_property import cached_property
from . import types
from ..const import COMPOSE_SPEC as VERSION
@@ -20,6 +24,7 @@ from ..utils import json_hash
from ..utils import parse_bytes
from ..utils import parse_nanoseconds_int
from ..utils import splitdrive
from ..version import ComposeVersion
from .environment import env_vars_from_file
from .environment import Environment
from .environment import split_env
@@ -132,6 +137,7 @@ ALLOWED_KEYS = DOCKER_CONFIG_KEYS + [
'logging',
'network_mode',
'platform',
'profiles',
'scale',
'stop_grace_period',
]
@@ -147,9 +153,14 @@ DOCKER_VALID_URL_PREFIXES = (
SUPPORTED_FILENAMES = [
'docker-compose.yml',
'docker-compose.yaml',
'compose.yml',
'compose.yaml',
]
DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml', 'docker-compose.override.yaml')
DEFAULT_OVERRIDE_FILENAMES = ('docker-compose.override.yml',
'docker-compose.override.yaml',
'compose.override.yml',
'compose.override.yaml')
log = logging.getLogger(__name__)
@@ -184,6 +195,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
def from_filename(cls, filename):
return cls(filename, load_yaml(filename))
@cached_property
def config_version(self):
version = self.config.get('version', None)
if isinstance(version, dict):
return V1
return ComposeVersion(version) if version else self.version
@cached_property
def version(self):
version = self.config.get('version', None)
@@ -222,15 +240,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
'Version "{}" in "{}" is invalid.'
.format(version, self.filename))
if version.startswith("1"):
version = V1
if version == V1:
if version.startswith("1"):
raise ConfigurationError(
'Version in "{}" is invalid. {}'
.format(self.filename, VERSION_EXPLANATION)
)
return version
return VERSION
def get_service(self, name):
return self.get_service_dicts()[name]
@@ -253,8 +269,10 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
return {} if self.version == V1 else self.config.get('configs', {})
class Config(namedtuple('_Config', 'version services volumes networks secrets configs')):
class Config(namedtuple('_Config', 'config_version version services volumes networks secrets configs')):
"""
:param config_version: configuration file version
:type config_version: int
:param version: configuration version
:type version: int
:param services: List of service description dictionaries
@@ -295,7 +313,16 @@ def find(base_dir, filenames, environment, override_dir=None):
if filenames:
filenames = [os.path.join(base_dir, f) for f in filenames]
else:
# search for compose files in the base dir and its parents
filenames = get_default_config_files(base_dir)
if not filenames and not override_dir:
# none found in base_dir and no override_dir defined
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
if not filenames:
# search for compose files in the project directory and its parents
filenames = get_default_config_files(override_dir)
if not filenames:
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
log.debug("Using configuration files: {}".format(",".join(filenames)))
return ConfigDetails(
@@ -326,7 +353,7 @@ def get_default_config_files(base_dir):
(candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, base_dir)
if not candidates:
raise ComposeFileNotFound(SUPPORTED_FILENAMES)
return None
winner = candidates[0]
@@ -365,6 +392,23 @@ def find_candidates_in_parent_dirs(filenames, path):
return (candidates, path)
def check_swarm_only_config(service_dicts):
warning_template = (
"Some services ({services}) use the '{key}' key, which will be ignored. "
"Compose does not support '{key}' configuration - use "
"`docker stack deploy` to deploy to a swarm."
)
key = 'configs'
services = [s for s in service_dicts if s.get(key)]
if services:
log.warning(
warning_template.format(
services=", ".join(sorted(s['name'] for s in services)),
key=key
)
)
def load(config_details, interpolate=True):
"""Load the configuration from a working directory and a list of
configuration files. Files are loaded in order, and merged on top
@@ -401,9 +445,10 @@ def load(config_details, interpolate=True):
for service_dict in service_dicts:
match_named_volumes(service_dict, volumes)
version = main_file.version
check_swarm_only_config(service_dicts)
return Config(version, service_dicts, volumes, networks, secrets, configs)
return Config(main_file.config_version, main_file.version,
service_dicts, volumes, networks, secrets, configs)
def load_mapping(config_files, get_func, entity_type, working_dir=None):
@@ -450,9 +495,6 @@ def format_device_option(entity_type, config):
device = config['driver_opts'].get('device')
if o and o == 'bind' and device:
fullpath = os.path.abspath(os.path.expanduser(device))
if not os.path.exists(fullpath):
raise ConfigurationError(
"Device path {} does not exist.".format(fullpath))
return fullpath
@@ -532,8 +574,7 @@ def process_config_section(config_file, config, section, environment, interpolat
config_file.version,
config,
section,
environment
)
environment)
else:
return config
@@ -1043,7 +1084,7 @@ def merge_service_dicts(base, override, version):
for field in [
'cap_add', 'cap_drop', 'expose', 'external_links',
'volumes_from', 'device_cgroup_rules',
'volumes_from', 'device_cgroup_rules', 'profiles',
]:
md.merge_field(field, merge_unique_items_lists, default=[])
@@ -1162,6 +1203,7 @@ def merge_reservations(base, override):
md.merge_scalar('cpus')
md.merge_scalar('memory')
md.merge_sequence('generic_resources', types.GenericResource.parse)
md.merge_field('devices', merge_unique_objects_lists, default=[])
return dict(md)

View File

@@ -54,9 +54,10 @@ class Environment(dict):
if base_dir is None:
return result
if env_file:
env_file_path = os.path.join(base_dir, env_file)
else:
env_file_path = os.path.join(base_dir, '.env')
env_file_path = os.path.join(os.getcwd(), env_file)
return cls(env_vars_from_file(env_file_path))
env_file_path = os.path.join(base_dir, '.env')
try:
return cls(env_vars_from_file(env_file_path))
except EnvFileNotFound:
@@ -113,13 +114,13 @@ class Environment(dict):
)
return super().get(key, *args, **kwargs)
def get_boolean(self, key):
def get_boolean(self, key, default=False):
# Convert a value to a boolean using "common sense" rules.
# Unset, empty, "0" and "false" (i-case) yield False.
# All other values yield True.
value = self.get(key)
if not value:
return False
return default
if value.lower() in ['0', 'false']:
return False
return True

View File

@@ -111,12 +111,14 @@ class TemplateWithDefaults(Template):
var, _, err = braced.partition(':?')
result = mapping.get(var)
if not result:
err = err or var
raise UnsetRequiredSubstitution(err)
return result
elif '?' == sep:
var, _, err = braced.partition('?')
if var in mapping:
return mapping.get(var)
err = err or var
raise UnsetRequiredSubstitution(err)
# Modified from python2.7/string.py
@@ -241,6 +243,7 @@ class ConversionMap:
service_path('healthcheck', 'disable'): to_boolean,
service_path('deploy', 'labels', PATH_JOKER): to_str,
service_path('deploy', 'replicas'): to_int,
service_path('deploy', 'placement', 'max_replicas_per_node'): to_int,
service_path('deploy', 'resources', 'limits', "cpus"): to_float,
service_path('deploy', 'update_config', 'parallelism'): to_int,
service_path('deploy', 'update_config', 'max_failure_ratio'): to_float,

View File

@@ -44,7 +44,7 @@ yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type)
def denormalize_config(config, image_digests=None):
result = {'version': str(config.version)}
result = {'version': str(config.config_version)}
denormalized_services = [
denormalize_service_dict(
service_dict,

View File

@@ -502,13 +502,13 @@ def get_schema_path():
def load_jsonschema(version):
suffix = "compose_spec"
name = "compose_spec"
if version == V1:
suffix = "v1"
name = "config_schema_v1"
filename = os.path.join(
get_schema_path(),
"config_schema_{}.json".format(suffix))
"{}.json".format(name))
if not os.path.exists(filename):
raise ConfigurationError(

View File

@@ -5,6 +5,7 @@ from .version import ComposeVersion
DEFAULT_TIMEOUT = 10
HTTP_TIMEOUT = 60
IS_WINDOWS_PLATFORM = (sys.platform == "win32")
IS_LINUX_PLATFORM = (sys.platform == "linux")
LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'
LABEL_ONE_OFF = 'com.docker.compose.oneoff'
LABEL_PROJECT = 'com.docker.compose.project'

View File

@@ -186,11 +186,6 @@ class Container:
def log_driver(self):
return self.get('HostConfig.LogConfig.Type')
@property
def has_api_logs(self):
log_type = self.log_driver
return not log_type or log_type in ('json-file', 'journald', 'local')
@property
def human_readable_health_status(self):
""" Generate UP status string with up time and health
@@ -204,11 +199,7 @@ class Container:
return status_string
def attach_log_stream(self):
"""A log stream can only be attached if the container uses a
json-file, journald or local log driver.
"""
if self.has_api_logs:
self.log_stream = self.attach(stdout=True, stderr=True, stream=True)
self.log_stream = self.attach(stdout=True, stderr=True, stream=True)
def get(self, key):
"""Return a value from the container or None if the value is not set.

View File

@@ -27,3 +27,8 @@ class NoHealthCheckConfigured(HealthCheckException):
service_name
)
)
class CompletedUnsuccessfully(Exception):
def __init__(self, container_id, exit_code):
self.msg = 'Container "{}" exited with code {}.'.format(container_id, exit_code)

View File

64
compose/metrics/client.py Normal file
View File

@@ -0,0 +1,64 @@
import os
from enum import Enum
import requests
from docker import ContextAPI
from docker.transport import UnixHTTPAdapter
from compose.const import IS_WINDOWS_PLATFORM
if IS_WINDOWS_PLATFORM:
from docker.transport import NpipeHTTPAdapter
class Status(Enum):
SUCCESS = "success"
FAILURE = "failure"
CANCELED = "canceled"
class MetricsSource:
CLI = "docker-compose"
if IS_WINDOWS_PLATFORM:
METRICS_SOCKET_FILE = 'npipe://\\\\.\\pipe\\docker_cli'
else:
METRICS_SOCKET_FILE = 'http+unix:///var/run/docker-cli.sock'
class MetricsCommand(requests.Session):
"""
Representation of a command in the metrics.
"""
def __init__(self, command,
context_type=None, status=Status.SUCCESS,
source=MetricsSource.CLI, uri=None):
super().__init__()
self.command = ("compose " + command).strip() if command else "compose --help"
self.context = context_type or ContextAPI.get_current_context().context_type or 'moby'
self.source = source
self.status = status.value
self.uri = uri or os.environ.get("METRICS_SOCKET_FILE", METRICS_SOCKET_FILE)
if IS_WINDOWS_PLATFORM:
self.mount("http+unix://", NpipeHTTPAdapter(self.uri))
else:
self.mount("http+unix://", UnixHTTPAdapter(self.uri))
def send_metrics(self):
try:
return self.post("http+unix://localhost/usage",
json=self.to_map(),
timeout=.05,
headers={'Content-Type': 'application/json'})
except Exception as e:
return e
def to_map(self):
return {
'command': self.command,
'context': self.context,
'source': self.source,
'status': self.status,
}

View File

@@ -0,0 +1,21 @@
import functools
from compose.metrics.client import MetricsCommand
from compose.metrics.client import Status
class metrics:
def __init__(self, command_name=None):
self.command_name = command_name
def __call__(self, fn):
@functools.wraps(fn,
assigned=functools.WRAPPER_ASSIGNMENTS,
updated=functools.WRAPPER_UPDATES)
def wrapper(*args, **kwargs):
if not self.command_name:
self.command_name = fn.__name__
result = fn(*args, **kwargs)
MetricsCommand(self.command_name, status=Status.SUCCESS).send_metrics()
return result
return wrapper

View File

@@ -11,10 +11,12 @@ from threading import Thread
from docker.errors import APIError
from docker.errors import ImageNotFound
from compose.cli.colors import AnsiMode
from compose.cli.colors import green
from compose.cli.colors import red
from compose.cli.signals import ShutdownException
from compose.const import PARALLEL_LIMIT
from compose.errors import CompletedUnsuccessfully
from compose.errors import HealthCheckFailed
from compose.errors import NoHealthCheckConfigured
from compose.errors import OperationFailedError
@@ -60,7 +62,8 @@ def parallel_execute_watch(events, writer, errors, results, msg, get_name, fail_
elif isinstance(exception, APIError):
errors[get_name(obj)] = exception.explanation
writer.write(msg, get_name(obj), 'error', red)
elif isinstance(exception, (OperationFailedError, HealthCheckFailed, NoHealthCheckConfigured)):
elif isinstance(exception, (OperationFailedError, HealthCheckFailed, NoHealthCheckConfigured,
CompletedUnsuccessfully)):
errors[get_name(obj)] = exception.msg
writer.write(msg, get_name(obj), 'error', red)
elif isinstance(exception, UpstreamError):
@@ -83,10 +86,7 @@ def parallel_execute(objects, func, get_name, msg, get_deps=None, limit=None, fa
objects = list(objects)
stream = sys.stderr
if ParallelStreamWriter.instance:
writer = ParallelStreamWriter.instance
else:
writer = ParallelStreamWriter(stream)
writer = ParallelStreamWriter.get_or_assign_instance(ParallelStreamWriter(stream))
for obj in objects:
writer.add_object(msg, get_name(obj))
@@ -243,6 +243,12 @@ def feed_queue(objects, func, get_deps, results, state, limiter):
'not processing'.format(obj)
)
results.put((obj, None, e))
except CompletedUnsuccessfully as e:
log.debug(
'Service(s) upstream of {} did not completed successfully - '
'not processing'.format(obj)
)
results.put((obj, None, e))
if state.is_done():
results.put(STOP)
@@ -259,19 +265,37 @@ class ParallelStreamWriter:
to jump to the correct line, and write over the line.
"""
noansi = False
lock = Lock()
default_ansi_mode = AnsiMode.AUTO
write_lock = Lock()
instance = None
instance_lock = Lock()
@classmethod
def set_noansi(cls, value=True):
cls.noansi = value
def get_instance(cls):
return cls.instance
def __init__(self, stream):
@classmethod
def get_or_assign_instance(cls, writer):
cls.instance_lock.acquire()
try:
if cls.instance is None:
cls.instance = writer
return cls.instance
finally:
cls.instance_lock.release()
@classmethod
def set_default_ansi_mode(cls, ansi_mode):
cls.default_ansi_mode = ansi_mode
def __init__(self, stream, ansi_mode=None):
if ansi_mode is None:
ansi_mode = self.default_ansi_mode
self.stream = stream
self.use_ansi_codes = ansi_mode.use_ansi_codes(stream)
self.lines = []
self.width = 0
ParallelStreamWriter.instance = self
def add_object(self, msg, obj_index):
if msg is None:
@@ -285,7 +309,7 @@ class ParallelStreamWriter:
return self._write_noansi(msg, obj_index, '')
def _write_ansi(self, msg, obj_index, status):
self.lock.acquire()
self.write_lock.acquire()
position = self.lines.index(msg + obj_index)
diff = len(self.lines) - position
# move up
@@ -297,7 +321,7 @@ class ParallelStreamWriter:
# move back down
self.stream.write("%c[%dB" % (27, diff))
self.stream.flush()
self.lock.release()
self.write_lock.release()
def _write_noansi(self, msg, obj_index, status):
self.stream.write(
@@ -310,17 +334,10 @@ class ParallelStreamWriter:
def write(self, msg, obj_index, status, color_func):
if msg is None:
return
if self.noansi:
self._write_noansi(msg, obj_index, status)
else:
if self.use_ansi_codes:
self._write_ansi(msg, obj_index, color_func(status))
def get_stream_writer():
instance = ParallelStreamWriter.instance
if instance is None:
raise RuntimeError('ParallelStreamWriter has not yet been instantiated')
return instance
else:
self._write_noansi(msg, obj_index, status)
def parallel_operation(containers, operation, options, message):

View File

@@ -39,6 +39,7 @@ from .service import Service
from .service import ServiceIpcMode
from .service import ServiceNetworkMode
from .service import ServicePidMode
from .utils import filter_attached_for_up
from .utils import microseconds_from_time_nano
from .utils import truncate_string
from .volume import ProjectVolumes
@@ -68,13 +69,15 @@ class Project:
"""
A collection of services.
"""
def __init__(self, name, services, client, networks=None, volumes=None, config_version=None):
def __init__(self, name, services, client, networks=None, volumes=None, config_version=None,
enabled_profiles=None):
self.name = name
self.services = services
self.client = client
self.volumes = volumes or ProjectVolumes({})
self.networks = networks or ProjectNetworks({}, False)
self.config_version = config_version
self.enabled_profiles = enabled_profiles or []
def labels(self, one_off=OneOffFilter.exclude, legacy=False):
name = self.name
@@ -86,7 +89,8 @@ class Project:
return labels
@classmethod
def from_config(cls, name, config_data, client, default_platform=None, extra_labels=None):
def from_config(cls, name, config_data, client, default_platform=None, extra_labels=None,
enabled_profiles=None):
"""
Construct a Project from a config.Config object.
"""
@@ -98,7 +102,7 @@ class Project:
networks,
use_networking)
volumes = ProjectVolumes.from_config(name, config_data, client)
project = cls(name, [], client, project_networks, volumes, config_data.version)
project = cls(name, [], client, project_networks, volumes, config_data.version, enabled_profiles)
for service_dict in config_data.services:
service_dict = dict(service_dict)
@@ -128,7 +132,7 @@ class Project:
config_data.secrets)
service_dict['scale'] = project.get_service_scale(service_dict)
service_dict['device_requests'] = project.get_device_requests(service_dict)
service_dict = translate_credential_spec_to_security_opt(service_dict)
service_dict, ignored_keys = translate_deploy_keys_to_container_config(
service_dict
@@ -185,7 +189,7 @@ class Project:
if name not in valid_names:
raise NoSuchService(name)
def get_services(self, service_names=None, include_deps=False):
def get_services(self, service_names=None, include_deps=False, auto_enable_profiles=True):
"""
Returns a list of this project's services filtered
by the provided list of names, or all services if service_names is None
@@ -198,15 +202,36 @@ class Project:
reordering as needed to resolve dependencies.
Raises NoSuchService if any of the named services do not exist.
Raises ConfigurationError if any service depended on is not enabled by active profiles
"""
# create a copy so we can *locally* add auto-enabled profiles later
enabled_profiles = self.enabled_profiles.copy()
if service_names is None or len(service_names) == 0:
service_names = self.service_names
auto_enable_profiles = False
service_names = [
service.name
for service in self.services
if service.enabled_for_profiles(enabled_profiles)
]
unsorted = [self.get_service(name) for name in service_names]
services = [s for s in self.services if s in unsorted]
if auto_enable_profiles:
# enable profiles of explicitly targeted services
for service in services:
for profile in service.get_profiles():
if profile not in enabled_profiles:
enabled_profiles.append(profile)
if include_deps:
services = reduce(self._inject_deps, services, [])
services = reduce(
lambda acc, s: self._inject_deps(acc, s, enabled_profiles),
services,
[]
)
uniques = []
[uniques.append(s) for s in services if s not in uniques]
@@ -331,6 +356,31 @@ class Project:
max_replicas))
return scale
def get_device_requests(self, service_dict):
deploy_dict = service_dict.get('deploy', None)
if not deploy_dict:
return
resources = deploy_dict.get('resources', None)
if not resources or not resources.get('reservations', None):
return
devices = resources['reservations'].get('devices')
if not devices:
return
for dev in devices:
count = dev.get("count", -1)
if not isinstance(count, int):
if count != "all":
raise ConfigurationError(
'Invalid value "{}" for devices count'.format(dev["count"]),
'(expected integer or "all")')
dev["count"] = -1
if 'capabilities' in dev:
dev['capabilities'] = [dev['capabilities']]
return devices
def start(self, service_names=None, **options):
containers = []
@@ -412,10 +462,12 @@ class Project:
self.remove_images(remove_image_type)
def remove_images(self, remove_image_type):
for service in self.get_services():
for service in self.services:
service.remove_image(remove_image_type)
def restart(self, service_names=None, **options):
# filter service_names by enabled profiles
service_names = [s.name for s in self.get_services(service_names)]
containers = self.containers(service_names, stopped=True)
parallel.parallel_execute(
@@ -438,7 +490,6 @@ class Project:
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")
@@ -594,12 +645,10 @@ class Project:
silent=False,
cli=False,
one_off=False,
attach_dependencies=False,
override_options=None,
):
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)
@@ -620,12 +669,17 @@ class Project:
one_off=service_names if one_off else [],
)
def do(service):
services_to_attach = filter_attached_for_up(
services,
service_names,
attach_dependencies,
lambda service: service.name)
def do(service):
return service.execute_convergence_plan(
plans[service.name],
timeout=timeout,
detached=detached,
detached=detached or (service not in services_to_attach),
scale_override=scale_override.get(service.name),
rescale=rescale,
start=start,
@@ -695,7 +749,7 @@ class Project:
return plans
def pull(self, service_names=None, ignore_pull_failures=False, parallel_pull=False, silent=False,
def pull(self, service_names=None, ignore_pull_failures=False, parallel_pull=True, silent=False,
include_deps=False):
services = self.get_services(service_names, include_deps)
@@ -729,7 +783,9 @@ class Project:
return
try:
writer = parallel.get_stream_writer()
writer = parallel.ParallelStreamWriter.get_instance()
if writer is None:
raise RuntimeError('ParallelStreamWriter has not yet been instantiated')
for event in strm:
if 'status' not in event:
continue
@@ -830,14 +886,26 @@ class Project:
)
)
def _inject_deps(self, acc, service):
def _inject_deps(self, acc, service, enabled_profiles):
dep_names = service.get_dependency_names()
if len(dep_names) > 0:
dep_services = self.get_services(
service_names=list(set(dep_names)),
include_deps=True
include_deps=True,
auto_enable_profiles=False
)
for dep in dep_services:
if not dep.enabled_for_profiles(enabled_profiles):
raise ConfigurationError(
'Service "{dep_name}" was pulled in as a dependency of '
'service "{service_name}" but is not enabled by the '
'active profiles. '
'You may fix this by adding a common profile to '
'"{dep_name}" and "{service_name}".'
.format(dep_name=dep.name, service_name=service.name)
)
else:
dep_services = []

View File

@@ -1,6 +1,5 @@
import enum
import itertools
import json
import logging
import os
import re
@@ -45,6 +44,7 @@ from .const import LABEL_VERSION
from .const import NANOCPUS_SCALE
from .const import WINDOWS_LONGPATH_PREFIX
from .container import Container
from .errors import CompletedUnsuccessfully
from .errors import HealthCheckFailed
from .errors import NoHealthCheckConfigured
from .errors import OperationFailedError
@@ -77,6 +77,7 @@ HOST_CONFIG_KEYS = [
'cpuset',
'device_cgroup_rules',
'devices',
'device_requests',
'dns',
'dns_search',
'dns_opt',
@@ -111,6 +112,7 @@ HOST_CONFIG_KEYS = [
CONDITION_STARTED = 'service_started'
CONDITION_HEALTHY = 'service_healthy'
CONDITION_COMPLETED_SUCCESSFULLY = 'service_completed_successfully'
class BuildError(Exception):
@@ -711,12 +713,13 @@ class Service:
'image_id': image_id(),
'links': self.get_link_names(),
'net': self.network_mode.id,
'ipc_mode': self.ipc_mode.mode,
'networks': self.networks,
'secrets': self.secrets,
'volumes_from': [
(v.source.name, v.mode)
for v in self.volumes_from if isinstance(v.source, Service)
],
]
}
def get_dependency_names(self):
@@ -752,6 +755,8 @@ class Service:
configs[svc] = lambda s: True
elif config['condition'] == CONDITION_HEALTHY:
configs[svc] = lambda s: s.is_healthy()
elif config['condition'] == CONDITION_COMPLETED_SUCCESSFULLY:
configs[svc] = lambda s: s.is_completed_successfully()
else:
# The config schema already prevents this, but it might be
# bypassed if Compose is called programmatically.
@@ -1016,6 +1021,7 @@ class Service:
privileged=options.get('privileged', False),
network_mode=self.network_mode.mode,
devices=options.get('devices'),
device_requests=options.get('device_requests'),
dns=options.get('dns'),
dns_opt=options.get('dns_opt'),
dns_search=options.get('dns_search'),
@@ -1101,8 +1107,9 @@ class Service:
'Impossible to perform platform-targeted builds for API version < 1.35'
)
builder = self.client if not cli else _CLIBuilder(progress)
build_output = builder.build(
builder = _ClientBuilder(self.client) if not cli else _CLIBuilder(progress)
return builder.build(
service=self,
path=path,
tag=self.image_name,
rm=rm,
@@ -1123,30 +1130,7 @@ class Service:
gzip=gzip,
isolation=build_opts.get('isolation', self.options.get('isolation', None)),
platform=self.platform,
)
try:
all_events = list(stream_output(build_output, output_stream))
except StreamOutputError as e:
raise BuildError(self, str(e))
# Ensure the HTTP connection is not reused for another
# streaming command, as the Docker daemon can sometimes
# complain about it
self.client.close()
image_id = None
for event in all_events:
if 'stream' in event:
match = re.search(r'Successfully built ([0-9a-f]+)', event.get('stream', ''))
if match:
image_id = match.group(1)
if image_id is None:
raise BuildError(self, event if all_events else 'Unknown')
return image_id
output_stream=output_stream)
def get_cache_from(self, build_opts):
cache_from = build_opts.get('cache_from', None)
@@ -1302,6 +1286,21 @@ class Service:
raise HealthCheckFailed(ctnr.short_id)
return result
def is_completed_successfully(self):
""" Check that all containers for this service has completed successfully
Returns false if at least one container does not exited and
raises CompletedUnsuccessfully exception if at least one container
exited with non-zero exit code.
"""
result = True
for ctnr in self.containers(stopped=True):
ctnr.inspect()
if ctnr.get('State.Status') != 'exited':
result = False
elif ctnr.exit_code != 0:
raise CompletedUnsuccessfully(ctnr.short_id, ctnr.exit_code)
return result
def _parse_proxy_config(self):
client = self.client
if 'proxies' not in client._general_configs:
@@ -1327,6 +1326,24 @@ class Service:
return result
def get_profiles(self):
if 'profiles' not in self.options:
return []
return self.options.get('profiles')
def enabled_for_profiles(self, enabled_profiles):
# if service has no profiles specified it is always enabled
if 'profiles' not in self.options:
return True
service_profiles = self.options.get('profiles')
for profile in enabled_profiles:
if profile in service_profiles:
return True
return False
def short_id_alias_exists(container, network):
aliases = container.get(
@@ -1770,20 +1787,77 @@ def rewrite_build_path(path):
return path
class _CLIBuilder:
def __init__(self, progress):
self._progress = progress
class _ClientBuilder:
def __init__(self, client):
self.client = client
def build(self, path, tag=None, quiet=False, fileobj=None,
def build(self, service, 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):
use_config_proxy=True, output_stream=sys.stdout):
build_output = self.client.build(
path=path,
tag=tag,
nocache=nocache,
rm=rm,
pull=pull,
forcerm=forcerm,
dockerfile=dockerfile,
labels=labels,
cache_from=cache_from,
buildargs=buildargs,
network_mode=network_mode,
target=target,
shmsize=shmsize,
extra_hosts=extra_hosts,
container_limits=container_limits,
gzip=gzip,
isolation=isolation,
platform=platform)
try:
all_events = list(stream_output(build_output, output_stream))
except StreamOutputError as e:
raise BuildError(service, str(e))
# Ensure the HTTP connection is not reused for another
# streaming command, as the Docker daemon can sometimes
# complain about it
self.client.close()
image_id = None
for event in all_events:
if 'stream' in event:
match = re.search(r'Successfully built ([0-9a-f]+)', event.get('stream', ''))
if match:
image_id = match.group(1)
if image_id is None:
raise BuildError(service, event if all_events else 'Unknown')
return image_id
class _CLIBuilder:
def __init__(self, progress):
self._progress = progress
def build(self, service, 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, output_stream=sys.stdout):
"""
Args:
service (str): Service to be built
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
@@ -1832,10 +1906,11 @@ class _CLIBuilder:
configuration file (``~/.docker/config.json`` by default)
contains a proxy configuration, the corresponding environment
variables will be set in the container being built.
output_stream (writer): stream to use for build logs
Returns:
A generator for the build output.
"""
if dockerfile:
if dockerfile and os.path.isdir(path):
dockerfile = os.path.join(path, dockerfile)
iidfile = tempfile.mktemp()
@@ -1853,35 +1928,29 @@ class _CLIBuilder:
command_builder.add_arg("--tag", tag)
command_builder.add_arg("--target", target)
command_builder.add_arg("--iidfile", iidfile)
command_builder.add_arg("--platform", platform)
command_builder.add_arg("--isolation", isolation)
if extra_hosts:
if isinstance(extra_hosts, dict):
extra_hosts = ["{}:{}".format(host, ip) for host, ip in extra_hosts.items()]
for host in extra_hosts:
command_builder.add_arg("--add-host", "{}".format(host))
args = command_builder.build([path])
magic_word = "Successfully built "
appear = False
with subprocess.Popen(args, stdout=subprocess.PIPE,
with subprocess.Popen(args, stdout=output_stream, stderr=sys.stderr,
universal_newlines=True) as p:
while True:
line = p.stdout.readline()
if not line:
break
if line.startswith(magic_word):
appear = True
yield json.dumps({"stream": line})
p.communicate()
if p.returncode != 0:
raise StreamOutputError()
raise BuildError(service, "Build failed")
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)})
return image_id
class _CommandBuilder:

View File

@@ -174,3 +174,18 @@ def truncate_string(s, max_chars=35):
if len(s) > max_chars:
return s[:max_chars - 2] + '...'
return s
def filter_attached_for_up(items, service_names, attach_dependencies=False,
item_to_service_name=lambda x: x):
"""This function contains the logic of choosing which services to
attach when doing docker-compose up. It may be used both with containers
and services, and any other entities that map to service names -
this mapping is provided by item_to_service_name."""
if attach_dependencies or not service_names:
return items
return [
item
for item in items if item_to_service_name(item) in service_names
]

View File

@@ -138,7 +138,7 @@ _docker_compose_config() {
;;
esac
COMPREPLY=( $( compgen -W "--hash --help --no-interpolate --quiet -q --resolve-image-digests --services --volumes" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--hash --help --no-interpolate --profiles --quiet -q --resolve-image-digests --services --volumes" -- "$cur" ) )
}
@@ -164,10 +164,18 @@ _docker_compose_docker_compose() {
_filedir "y?(a)ml"
return
;;
--ansi)
COMPREPLY=( $( compgen -W "never always auto" -- "$cur" ) )
return
;;
--log-level)
COMPREPLY=( $( compgen -W "debug info warning error critical" -- "$cur" ) )
return
;;
--profile)
COMPREPLY=( $( compgen -W "$(__docker_compose_q config --profiles)" -- "$cur" ) )
return
;;
--project-directory)
_filedir -d
return
@@ -290,7 +298,7 @@ _docker_compose_logs() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--follow -f --help --no-color --tail --timestamps -t" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--follow -f --help --no-color --no-log-prefix --tail --timestamps -t" -- "$cur" ) )
;;
*)
__docker_compose_complete_services
@@ -545,7 +553,7 @@ _docker_compose_up() {
case "$cur" in
-*)
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" ) )
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-log-prefix --no-recreate --no-start --renew-anon-volumes -V --remove-orphans --scale --timeout -t" -- "$cur" ) )
;;
*)
__docker_compose_complete_services
@@ -614,9 +622,11 @@ _docker_compose() {
--tlskey
"
# These options are require special treatment when searching the command.
# These options require special treatment when searching the command.
local top_level_options_with_args="
--ansi
--log-level
--profile
"
COMPREPLY=()

View File

@@ -21,5 +21,7 @@ complete -c docker-compose -l tlscert -r -d 'Path to TLS certif
complete -c docker-compose -l tlskey -r -d 'Path to TLS key file'
complete -c docker-compose -l tlsverify -d 'Use TLS and verify the remote'
complete -c docker-compose -l skip-hostname-check -d "Don't check the daemon's hostname against the name specified in the client certificate (for example if your docker host is an IP address)"
complete -c docker-compose -l no-ansi -d 'Do not print ANSI control characters'
complete -c docker-compose -l ansi -a 'never always auto' -d 'Control when to print ANSI control characters'
complete -c docker-compose -s h -l help -d 'Print usage'
complete -c docker-compose -s v -l version -d 'Print version and exit'

View File

@@ -342,6 +342,7 @@ _docker-compose() {
'--verbose[Show more output]' \
'--log-level=[Set log level]:level:(DEBUG INFO WARNING ERROR CRITICAL)' \
'--no-ansi[Do not print ANSI control characters]' \
'--ansi=[Control when to print ANSI control characters]:when:(never always auto)' \
'(-H --host)'{-H,--host}'[Daemon socket to connect to]:host:' \
'--tls[Use TLS; implied by --tlsverify]' \
'--tlscacert=[Trust certs signed only by this CA]:ca path:' \

View File

@@ -23,8 +23,8 @@ exe = EXE(pyz,
'DATA'
),
(
'compose/config/config_schema_compose_spec.json',
'compose/config/config_schema_compose_spec.json',
'compose/config/compose_spec.json',
'compose/config/compose_spec.json',
'DATA'
),
(

View File

@@ -32,8 +32,8 @@ coll = COLLECT(exe,
'DATA'
),
(
'compose/config/config_schema_compose_spec.json',
'compose/config/config_schema_compose_spec.json',
'compose/config/compose_spec.json',
'compose/config/compose_spec.json',
'DATA'
),
(

View File

@@ -0,0 +1,474 @@
There are three legacy versions of the Compose file format:
- Version 1. This is specified by omitting a `version` key at the root of the YAML.
- Version 2.x. This is specified with a `version: '2'` or `version: '2.1'`, etc., entry at the root of the YAML.
- Version 3.x, designed to be cross-compatible between Compose and the Docker Engine's
[swarm mode](https://docs.docker.com/engine/swarm/). This is specified with a `version: '3'` or `version: '3.1'`, etc., entry at the root of the YAML.
The latest and recommended version of the Compose file format is defined by the [Compose Specification](https://docs.docker.com/compose/compose-file/). This format merges the 2.x and 3.x versions and is implemented by **Compose 1.27.0+**.
> **Note**
>
> If you're using [multiple Compose files](https://docs.docker.com/compose/multiple-compose-files/) or
> [extending services](https://docs.docker.com/compose/multiple-compose-files/extends/),
> each file must be of the same version - you cannot, for example,
> mix version 1 and 2 in a single project.
Several things differ depending on which version you use:
- The structure and permitted configuration keys
- The minimum Docker Engine version you must be running
- Compose's behaviour with regards to networking
These differences are explained below.
### Version 2
Compose files using the version 2 syntax must indicate the version number at
the root of the document. All [services](compose-file-v2.md#service-configuration-reference)
must be declared under the `services` key.
Version 2 files are supported by **Compose 1.6.0+** and require a Docker Engine
of version **1.10.0+**.
Named [volumes](compose-file-v2.md#volume-configuration-reference) can be declared under the
`volumes` key, and [networks](compose-file-v2.md#network-configuration-reference) can be declared
under the `networks` key.
By default, every container joins an application-wide default network, and is
discoverable at a hostname that's the same as the service name. This means
[links](compose-file-v2.md#links) are largely unnecessary. For more details, see
[Networking in Compose](https://docs.docker.com/compose/networking/).
> **Note**
>
> With Compose version 2, when specifying the Compose file version to use, make sure to
> specify both the _major_ and _minor_ numbers. If no minor version is given,
> `0` is used by default and not the latest minor version. As a result, features added in later versions will not be supported. For example:
>
> ```yaml
> version: "2"
> ```
>
> is equivalent to:
>
> ```yaml
> version: "2.0"
> ```
Simple example:
version: "{{% param "compose_file_v2" %}}"
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
redis:
image: redis
A more extended example, defining volumes and networks:
version: "{{% param "compose_file_v2" %}}"
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
networks:
- front-tier
- back-tier
redis:
image: redis
volumes:
- redis-data:/var/lib/redis
networks:
- back-tier
volumes:
redis-data:
driver: local
networks:
front-tier:
driver: bridge
back-tier:
driver: bridge
Several other options were added to support networking, such as:
* [`aliases`](compose-file-v2.md#aliases)
* The [`depends_on`](compose-file-v2.md#depends_on) option can be used in place of links to indicate dependencies
between services and startup order.
version: "{{% param "compose_file_v2" %}}"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
* [`ipv4_address`, `ipv6_address`](compose-file-v2.md#ipv4_address-ipv6_address)
[Variable substitution](compose-file-v2.md#variable-substitution) also was added in Version 2.
### Version 2.1
An upgrade of [version 2](#version-2) that introduces new parameters only
available with Docker Engine version **1.12.0+**. Version 2.1 files are
supported by **Compose 1.9.0+**.
Introduces the following additional parameters:
- [`link_local_ips`](compose-file-v2.md#link_local_ips)
- [`isolation`](compose-file-v2.md#isolation-1) in build configurations and
service definitions
- `labels` for [volumes](compose-file-v2.md#volume-configuration-reference),
[networks](compose-file-v2.md#network-configuration-reference), and
[build](compose-file-v3.md#build)
- `name` for [volumes](compose-file-v2.md#volume-configuration-reference)
- [`userns_mode`](compose-file-v2.md#userns_mode)
- [`healthcheck`](compose-file-v2.md#healthcheck)
- [`sysctls`](compose-file-v2.md#sysctls)
- [`pids_limit`](compose-file-v2.md#pids_limit)
- [`oom_kill_disable`](compose-file-v2.md#cpu-and-other-resources)
- [`cpu_period`](compose-file-v2.md#cpu-and-other-resources)
### Version 2.2
An upgrade of [version 2.1](#version-21) that introduces new parameters only
available with Docker Engine version **1.13.0+**. Version 2.2 files are
supported by **Compose 1.13.0+**. This version also allows you to specify
default scale numbers inside the service's configuration.
Introduces the following additional parameters:
- [`init`](compose-file-v2.md#init)
- [`scale`](compose-file-v2.md#scale)
- [`cpu_rt_runtime` and `cpu_rt_period`](compose-file-v2.md#cpu_rt_runtime-cpu_rt_period)
- [`network`](compose-file-v2.md#network) for [build configurations](compose-file-v2.md#build)
### Version 2.3
An upgrade of [version 2.2](#version-22) that introduces new parameters only
available with Docker Engine version **17.06.0+**. Version 2.3 files are
supported by **Compose 1.16.0+**.
Introduces the following additional parameters:
- [`target`](compose-file-v2.md#target), [`extra_hosts`](compose-file-v2.md#extra_hosts-1) and
[`shm_size`](compose-file-v2.md#shm_size) for [build configurations](compose-file-v2.md#build)
- `start_period` for [`healthchecks`](compose-file-v2.md#healthcheck)
- ["Long syntax" for volumes](compose-file-v2.md#long-syntax)
- [`runtime`](compose-file-v2.md#runtime) for service definitions
- [`device_cgroup_rules`](compose-file-v2.md#device_cgroup_rules)
### Version 2.4
An upgrade of [version 2.3](#version-23) that introduces new parameters only
available with Docker Engine version **17.12.0+**. Version 2.4 files are
supported by **Compose 1.21.0+**.
Introduces the following additional parameters:
- [`platform`](compose-file-v2.md#platform) for service definitions
- Support for extension fields at the root of service, network, and volume
definitions
### Version 3
Designed to be cross-compatible between Compose and the Docker Engine's
[swarm mode](/engine/swarm/), version 3 removes several options and adds
several more.
- Removed: `volume_driver`, `volumes_from`, `cpu_shares`, `cpu_quota`,
`cpuset`, `mem_limit`, `memswap_limit`, `extends`, `group_add`. See
the [upgrading](#upgrading) guide for how to migrate away from these.
- Added: [deploy](compose-file-v3.md#deploy)
If only the major version is given (`version: '3'`),
the latest minor version is used by default.
### Version 3.1
An upgrade of [version 3](#version-3) that introduces new parameters only
available with Docker Engine version **1.13.1+**, and higher.
Introduces the following additional parameters:
- [`secrets`](compose-file-v3.md#secrets)
### Version 3.2
An upgrade of [version 3](#version-3) that introduces new parameters only
available with Docker Engine version **17.04.0+**, and higher.
Introduces the following additional parameters:
- [`cache_from`](compose-file-v3.md#cache_from) in [build configurations](compose-file-v3.md#build)
- Long syntax for [ports](compose-file-v3.md#ports) and [volume mounts](compose-file-v3.md#volumes)
- [`attachable`](compose-file-v3.md#attachable) network driver option
- [deploy `endpoint_mode`](compose-file-v3.md#endpoint_mode)
- [deploy placement `preference`](compose-file-v3.md#placement)
### Version 3.3
An upgrade of [version 3](#version-3) that introduces new parameters only
available with Docker Engine version **17.06.0+**, and higher.
Introduces the following additional parameters:
- [build `labels`](compose-file-v3.md#build)
- [`credential_spec`](compose-file-v3.md#credential_spec)
- [`configs`](compose-file-v3.md#configs)
### Version 3.4
An upgrade of [version 3](#version-3) that introduces new parameters. It is
only available with Docker Engine version **17.09.0** and higher.
Introduces the following additional parameters:
- [`target`](compose-file-v3.md#target) and [`network`](compose-file-v3.md#network) in
[build configurations](compose-file-v3.md#build)
- `start_period` for [`healthchecks`](compose-file-v3.md#healthcheck)
- `order` for [update configurations](compose-file-v3.md#update_config)
- `name` for [volumes](compose-file-v3.md#volume-configuration-reference)
### Version 3.5
An upgrade of [version 3](#version-3) that introduces new parameters. It is
only available with Docker Engine version **17.12.0** and higher.
Introduces the following additional parameters:
- [`isolation`](compose-file-v3.md#isolation) in service definitions
- `name` for networks, secrets and configs
- `shm_size` in [build configurations](compose-file-v3.md#build)
### Version 3.6
An upgrade of [version 3](#version-3) that introduces new parameters. It is
only available with Docker Engine version **18.02.0** and higher.
Introduces the following additional parameters:
- [`tmpfs` size](compose-file-v3.md#long-syntax-3) for `tmpfs`-type mounts
### Version 3.7
An upgrade of [version 3](#version-3) that introduces new parameters. It is
only available with Docker Engine version **18.06.0** and higher.
Introduces the following additional parameters:
- [`init`](compose-file-v3.md#init) in service definitions
- [`rollback_config`](compose-file-v3.md#rollback_config) in deploy configurations
- Support for extension fields at the root of service, network, volume, secret
and config definitions
### Version 3.8
An upgrade of [version 3](#version-3) that introduces new parameters. It is
only available with Docker Engine version **19.03.0** and higher.
Introduces the following additional parameters:
- [`max_replicas_per_node`](compose-file-v3.md#max_replicas_per_node) in placement
configurations
- `template_driver` option for [config](compose-file-v3.md#configs-configuration-reference)
and [secret](compose-file-v3.md#secrets-configuration-reference) configurations. This
option is only supported when deploying swarm services using
`docker stack deploy`.
- `driver` and `driver_opts` option for [secret](compose-file-v3.md#secrets-configuration-reference)
configurations. This option is only supported when deploying swarm services
using `docker stack deploy`.
### Version 1 (Deprecated)
Compose versions below 1.6.x are
Compose files that do not declare a version are considered "version 1". In those
files, all the [services](compose-file-v3.md#service-configuration-reference) are
declared at the root of the document.
Version 1 is supported by Compose up to 1.6.x** and has been deprecated.
Version 1 files cannot declare named
[volumes](compose-file-v3.md#volume-configuration-reference), [networks](compose-file-v3.md#network-configuration-reference) or
[build arguments](compose-file-v3.md#args).
Compose does not take advantage of [networking](https://docs.docker.com/compose/networking/) when you
use version 1: every container is placed on the default `bridge` network and is
reachable from every other container at its IP address. You need to use
`links` to enable discovery between containers.
Example:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
links:
- redis
redis:
image: redis
## Upgrading
### Version 2.x to 3.x
Between versions 2.x and 3.x, the structure of the Compose file is the same, but
several options have been removed:
- `volume_driver`: Instead of setting the volume driver on the service, define
a volume using the
[top-level `volumes` option](compose-file-v3.md#volume-configuration-reference)
and specify the driver there.
version: "3.8"
services:
db:
image: postgres
volumes:
- data:/var/lib/postgresql/data
volumes:
data:
driver: mydriver
- `volumes_from`: To share a volume between services, define it using the
[top-level `volumes` option](compose-file-v3.md#volume-configuration-reference)
and reference it from each service that shares it using the
[service-level `volumes` option](compose-file-v3.md#driver).
- `cpu_shares`, `cpu_quota`, `cpuset`, `mem_limit`, `memswap_limit`: These
have been replaced by the [resources](compose-file-v3.md#resources) key under
`deploy`. `deploy` configuration only takes effect when using
`docker stack deploy`, and is ignored by `docker-compose`.
- `extends`: This option has been removed for `version: "3.x"` Compose files.
For more information on `extends`, see
[Extending services](https://docs.docker.com/compose/multiple-compose-files/extends/).
- `group_add`: This option has been removed for `version: "3.x"` Compose files.
- `pids_limit`: This option has not been introduced in `version: "3.x"` Compose files.
- `link_local_ips` in `networks`: This option has not been introduced in
`version: "3.x"` Compose files.
#### Compatibility mode
`docker-compose` 1.20.0 introduces a new `--compatibility` flag designed to
help developers transition to version 3 more easily. When enabled,
`docker-compose` reads the `deploy` section of each service's definition and
attempts to translate it into the equivalent version 2 parameter. Currently,
the following deploy keys are translated:
- [resources](compose-file-v3.md#resources) limits and memory reservations
- [replicas](compose-file-v3.md#replicas)
- [restart_policy](compose-file-v3.md#restart_policy) `condition` and `max_attempts`
All other keys are ignored and produce a warning if present. You can review
the configuration that will be used to deploy by using the `--compatibility`
flag with the `config` command.
> Do not use this in production
>
> We recommend against using `--compatibility` mode in production. The
> resulting configuration is only an approximate using non-Swarm mode
> properties, it may produce unexpected results.
### Version 1 to 2.x
In the majority of cases, moving from version 1 to 2 is a very simple process:
1. Indent the whole file by one level and put a `services:` key at the top.
2. Add a `version: '2'` line at the top of the file.
It's more complicated if you're using particular configuration features:
- `dockerfile`: This now lives under the `build` key:
build:
context: .
dockerfile: Dockerfile-alternate
- `log_driver`, `log_opt`: These now live under the `logging` key:
logging:
driver: syslog
options:
syslog-address: "tcp://192.168.0.42:123"
- `links` with environment variables: environment variables created by
links, such as `CONTAINERNAME_PORT`, ` have been deprecated for some time. In the new Docker network system,
they have been removed. You should either connect directly to the
appropriate hostname or set the relevant environment variable yourself,
using the link hostname:
web:
links:
- db
environment:
- DB_PORT=tcp://db:5432
- `external_links`: Compose uses Docker networks when running version 2
projects, so links behave slightly differently. In particular, two
containers must be connected to at least one network in common in order to
communicate, even if explicitly linked together.
Either connect the external container to your app's
[default network](https://docs.docker.com/compose/networking/), or connect both the external container and
your service's containers to an
[external network](https://docs.docker.com/compose/networking/).
- `net`: This is now replaced by [network_mode](compose-file-v3.md#network_mode):
net: host -> network_mode: host
net: bridge -> network_mode: bridge
net: none -> network_mode: none
If you're using `net: "container:[service name]"`, you must now use
`network_mode: "service:[service name]"` instead.
net: "container:web" -> network_mode: "service:web"
If you're using `net: "container:[container name/id]"`, the value does not
need to change.
net: "container:cont-name" -> network_mode: "container:cont-name"
net: "container:abc12345" -> network_mode: "container:abc12345"
- `volumes` with named volumes: these must now be explicitly declared in a
top-level `volumes` section of your Compose file. If a service mounts a
named volume called `data`, you must declare a `data` volume in your
top-level `volumes` section. The whole file might look like this:
version: "{{% param "compose_file_v2" %}}"
services:
db:
image: postgres
volumes:
- data:/var/lib/postgresql/data
volumes:
data: {}
By default, Compose creates a volume whose name is prefixed with your
project name. If you want it to just be called `data`, declare it as
external:
volumes:
data:
external: true

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
# The docs have been moved!
The documentation for Compose has been merged into
[the general documentation repo](https://github.com/docker/docker.github.io).
The docs for Compose are now here:
https://github.com/docker/docker.github.io/tree/master/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.
As always, the docs remain open-source and we appreciate your feedback and
pull requests!

437
logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 132 KiB

View File

@@ -1 +1 @@
pyinstaller==3.6
pyinstaller==4.1

View File

@@ -1,9 +1,9 @@
Click==7.1.2
coverage==5.2.1
ddt==1.4.1
coverage==5.5
ddt==1.4.2
flake8==3.8.3
gitpython==3.1.7
gitpython==3.1.11
mock==3.0.5
pytest==6.0.1; python_version >= '3.5'
pytest==6.2.4; python_version >= '3.5'
pytest==4.6.5; python_version < '3.5'
pytest-cov==2.10.1

View File

@@ -1,19 +1,19 @@
altgraph==0.17
appdirs==1.4.4
attrs==20.1.0
bcrypt==3.1.7
cffi==1.14.1
cryptography==3.0
attrs==20.3.0
bcrypt==3.2.0
cffi==1.14.4
cryptography==3.3.2
distlib==0.3.1
entrypoints==0.3
filelock==3.0.12
gitdb2==4.0.2
mccabe==0.6.1
more-itertools==8.4.0; python_version >= '3.5'
more-itertools==8.6.0; python_version >= '3.5'
more-itertools==5.0.0; python_version < '3.5'
packaging==20.4
packaging==20.9
pluggy==0.13.1
py==1.9.0
py==1.10.0
pycodestyle==2.6.0
pycparser==2.20
pyflakes==2.2.0
@@ -23,6 +23,6 @@ pyrsistent==0.16.0
smmap==3.0.4
smmap2==3.0.1
toml==0.10.1
tox==3.19.0
virtualenv==20.0.30
tox==3.21.2
virtualenv==20.4.0
wcwidth==0.2.5

View File

@@ -1,23 +1,22 @@
backports.shutil_get_terminal_size==1.0.0
cached-property==1.5.1
certifi==2020.6.20
cached-property==1.5.1; python_version < '3.8'
certifi==2021.5.30
chardet==3.0.4
colorama==0.4.3; sys_platform == 'win32'
colorama==0.4.4; sys_platform == 'win32'
distro==1.5.0
docker==4.3.1
docker==5.0.0
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
idna==2.10
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'
paramiko==2.7.2
PySocks==1.7.1
python-dotenv==0.14.0
PyYAML==5.3.1
requests==2.24.0
texttable==1.6.2
urllib3==1.25.10; python_version == '3.3'
websocket-client==0.57.0
python-dotenv==0.17.0
pywin32==301; sys_platform == 'win32'
PyYAML==5.4.1
requests==2.25.1
texttable==1.6.3
urllib3==1.26.5; python_version == '3.3'
websocket-client==1.1.0

View File

@@ -5,14 +5,12 @@ set -ex
./script/clean
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
docker build . \
--target bin \
--build-arg DISTRO=debian \
--build-arg GIT_COMMIT="${DOCKER_COMPOSE_GITSHA}" \
--output 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}"
# Ensure that we output the binary with the same name as we did before
mv dist/docker-compose-linux-amd64 "dist/docker-compose-Linux-${ARCH}"

View File

@@ -24,7 +24,7 @@ if [ ! -z "${BUILD_BOOTLOADER}" ]; then
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
git checkout v4.1
"${VENV}"/bin/python3 ./waf configure --no-lsb all
"${VENV}"/bin/pip3 install ..
cd "${CODE_PATH}"

View File

@@ -13,6 +13,6 @@ IMAGE="docker/compose-tests"
DOCKER_COMPOSE_GITSHA="$(script/build/write-git-sha)"
docker build -t "${IMAGE}:${TAG}" . \
--target build \
--build-arg BUILD_PLATFORM="debian" \
--build-arg DISTRO="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.7.x:
# 2. Install Python 3.9.x:
#
# https://www.python.org/downloads/
#
# 3. Append ";C:\Python37;C:\Python37\Scripts" to the "Path" environment variable:
# 3. Append ";C:\Python39;C:\Python39\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==20.0.30'
# $ pip install 'virtualenv==20.2.2'
# $ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
#
# 5. Clone the repository:
@@ -39,7 +39,7 @@ if (Test-Path venv) {
Get-ChildItem -Recurse -Include *.pyc | foreach ($_) { Remove-Item $_.FullName }
# Create virtualenv
virtualenv -p C:\Python37\python.exe .\venv
virtualenv -p C:\Python39\python.exe .\venv
# pip and pyinstaller generate lots of warnings, so we need to ignore them
$ErrorActionPreference = "Continue"

View File

@@ -20,4 +20,3 @@ This should trigger a new CI build on the new tag. When the CI finishes with the
4. In case of a GA version, please update `docker-compose`s release notes and version on [github documentation repository](https://github.com/docker/docker.github.io):
- [Release Notes](https://github.com/docker/docker.github.io/blob/master/compose/release-notes.md)
- [Config version](https://github.com/docker/docker.github.io/blob/master/_config.yml)
- [Config authoring version](https://github.com/docker/docker.github.io/blob/master/_config_authoring.yml)

View File

@@ -21,10 +21,10 @@ IMAGE="docker/compose:$VERSION"
# Setup options for connecting to docker host
if [ -z "$DOCKER_HOST" ]; then
DOCKER_HOST="/var/run/docker.sock"
DOCKER_HOST='unix:///var/run/docker.sock'
fi
if [ -S "$DOCKER_HOST" ]; then
DOCKER_ADDR="-v $DOCKER_HOST:$DOCKER_HOST -e DOCKER_HOST"
if [ -S "${DOCKER_HOST#unix://}" ]; then
DOCKER_ADDR="-v ${DOCKER_HOST#unix://}:${DOCKER_HOST#unix://} -e DOCKER_HOST"
else
DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH"
fi
@@ -44,13 +44,34 @@ fi
if [ -n "$COMPOSE_PROJECT_NAME" ]; then
COMPOSE_OPTIONS="-e COMPOSE_PROJECT_NAME $COMPOSE_OPTIONS"
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 -e HOME" # Pass in HOME to share docker.config and allow ~/-relative paths to work.
fi
i=$#
while [ $i -gt 0 ]; do
arg=$1
i=$((i - 1))
shift
case "$arg" in
-f|--file)
value=$1
i=$((i - 1))
shift
set -- "$@" "$arg" "$value"
file_dir=$(realpath "$(dirname "$value")")
VOLUMES="$VOLUMES -v $file_dir:$file_dir"
;;
*) set -- "$@" "$arg" ;;
esac
done
# Setup environment variables for compose config and context
ENV_OPTIONS=$(printenv | sed -E "/^PATH=.*/d; s/^/-e /g; s/=.*//g; s/\n/ /g")
# Only allocate tty if we detect one
if [ -t 0 ] && [ -t 1 ]; then
@@ -67,4 +88,4 @@ if docker info --format '{{json .SecurityOptions}}' 2>/dev/null | grep -q 'name=
fi
# shellcheck disable=SC2086
exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" $IMAGE "$@"
exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $ENV_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.1g
OPENSSL_VERSION=1.1.1h
OPENSSL_URL=https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
OPENSSL_SHA1=b213a293f2127ec3e323fb3cfc0c9807664fd997
OPENSSL_SHA1=8d0d099e8973ec851368c8c775e05e1eadca1794
PYTHON_VERSION=3.7.7
PYTHON_VERSION=3.9.0
PYTHON_URL=https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
PYTHON_SHA1=8e9968663a214aea29659ba9dfa959e8a7d82b39
PYTHON_SHA1=5744a10ba989d2badacbab3c00cdcb83c83106c7
#
# Install prerequisites.
@@ -36,7 +36,7 @@ if ! [ -x "$(command -v python3)" ]; then
brew install python3
fi
if ! [ -x "$(command -v virtualenv)" ]; then
pip3 install virtualenv==20.0.30
pip3 install virtualenv==20.2.2
fi
#

View File

@@ -21,7 +21,6 @@ elif [ "$DOCKER_VERSIONS" == "all" ]; then
DOCKER_VERSIONS=$($get_versions -n 2 recent)
fi
BUILD_NUMBER=${BUILD_NUMBER-$USER}
PY_TEST_VERSIONS=${PY_TEST_VERSIONS:-py37}
@@ -39,17 +38,23 @@ for version in $DOCKER_VERSIONS; do
trap "on_exit" EXIT
repo="dockerswarm/dind"
docker run \
-d \
--name "$daemon_container" \
--privileged \
--volume="/var/lib/docker" \
"$repo:$version" \
-e "DOCKER_TLS_CERTDIR=" \
"docker:$version-dind" \
dockerd -H tcp://0.0.0.0:2375 $DOCKER_DAEMON_ARGS \
2>&1 | tail -n 10
docker exec "$daemon_container" sh -c "apk add --no-cache git"
# copy docker config from host for authentication with Docker Hub
docker exec "$daemon_container" sh -c "mkdir /root/.docker"
docker cp /root/.docker/config.json $daemon_container:/root/.docker/config.json
docker exec "$daemon_container" sh -c "chmod 644 /root/.docker/config.json"
docker run \
--rm \
--tty \

View File

@@ -25,14 +25,13 @@ def find_version(*file_paths):
install_requires = [
'cached-property >= 1.2.0, < 2',
'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',
'distro >= 1.5.0, < 2',
'docker[ssh] >= 4.3.1, < 5',
'docker[ssh] >= 5',
'dockerpty >= 0.4.1, < 1',
'jsonschema >= 2.5.1, < 4',
'python-dotenv >= 0.13.0, < 1',
@@ -50,6 +49,7 @@ if sys.version_info[:2] < (3, 4):
extras_require = {
':python_version < "3.5"': ['backports.ssl_match_hostname >= 3.5, < 4'],
':python_version < "3.8"': ['cached-property >= 1.2.0, < 2'],
':sys_platform == "win32"': ['colorama >= 0.4, < 1'],
'socks': ['PySocks >= 1.5.6, != 1.5.7, < 2'],
'tests': tests_require,
@@ -102,5 +102,7 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
],
)

View File

@@ -58,13 +58,16 @@ COMPOSE_COMPATIBILITY_DICT = {
}
def start_process(base_dir, options):
def start_process(base_dir, options, executable=None, env=None):
executable = executable or DOCKER_COMPOSE_EXECUTABLE
proc = subprocess.Popen(
[DOCKER_COMPOSE_EXECUTABLE] + options,
[executable] + options,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=base_dir)
cwd=base_dir,
env=env,
)
print("Running process: %s" % proc.pid)
return proc
@@ -78,9 +81,10 @@ def wait_on_process(proc, returncode=0, stdin=None):
return ProcessResult(stdout.decode('utf-8'), stderr.decode('utf-8'))
def dispatch(base_dir, options, project_options=None, returncode=0, stdin=None):
def dispatch(base_dir, options,
project_options=None, returncode=0, stdin=None, executable=None, env=None):
project_options = project_options or []
proc = start_process(base_dir, project_options + options)
proc = start_process(base_dir, project_options + options, executable=executable, env=env)
return wait_on_process(proc, returncode=returncode, stdin=stdin)
@@ -233,6 +237,11 @@ class CLITestCase(DockerClientTestCase):
result = self.dispatch(['-H=tcp://doesnotexist:8000', 'ps'], returncode=1)
assert "Couldn't connect to Docker daemon" in result.stderr
def test_config_list_profiles(self):
self.base_dir = 'tests/fixtures/config-profiles'
result = self.dispatch(['config', '--profiles'])
assert set(result.stdout.rstrip().split('\n')) == {'debug', 'frontend', 'gui'}
def test_config_list_services(self):
self.base_dir = 'tests/fixtures/v2-full'
result = self.dispatch(['config', '--services'])
@@ -359,7 +368,7 @@ services:
'web': {
'command': 'true',
'image': 'alpine:latest',
'ports': ['5643/tcp', '9999/tcp']
'ports': [{'target': 5643}, {'target': 9999}]
}
}
}
@@ -374,7 +383,7 @@ services:
'web': {
'command': 'false',
'image': 'alpine:latest',
'ports': ['5644/tcp', '9998/tcp']
'ports': [{'target': 5644}, {'target': 9998}]
}
}
}
@@ -389,7 +398,7 @@ services:
'web': {
'command': 'echo uwu',
'image': 'alpine:3.10.1',
'ports': ['3341/tcp', '4449/tcp']
'ports': [{'target': 3341}, {'target': 4449}]
}
}
}
@@ -783,7 +792,11 @@ services:
assert BUILD_CACHE_TEXT not in result.stdout
assert BUILD_PULL_TEXT in result.stdout
@mock.patch.dict(os.environ)
def test_build_log_level(self):
os.environ['COMPOSE_DOCKER_CLI_BUILD'] = '0'
os.environ['DOCKER_BUILDKIT'] = '0'
self.test_env_file_relative_to_compose_file()
self.base_dir = 'tests/fixtures/simple-dockerfile'
result = self.dispatch(['--log-level', 'warning', 'build', 'simple'])
assert result.stderr == ''
@@ -845,13 +858,17 @@ services:
for c in self.project.client.containers(all=True):
self.addCleanup(self.project.client.remove_container, c, force=True)
@mock.patch.dict(os.environ)
def test_build_shm_size_build_option(self):
os.environ['COMPOSE_DOCKER_CLI_BUILD'] = '0'
pull_busybox(self.client)
self.base_dir = 'tests/fixtures/build-shm-size'
result = self.dispatch(['build', '--no-cache'], None)
assert 'shm_size: 96' in result.stdout
@mock.patch.dict(os.environ)
def test_build_memory_build_option(self):
os.environ['COMPOSE_DOCKER_CLI_BUILD'] = '0'
pull_busybox(self.client)
self.base_dir = 'tests/fixtures/build-memory'
result = self.dispatch(['build', '--no-cache', '--memory', '96m', 'service'], None)
@@ -1719,6 +1736,98 @@ services:
shareable_mode_container = self.project.get_service('shareable').containers()[0]
assert shareable_mode_container.get('HostConfig.IpcMode') == 'shareable'
def test_profiles_up_with_no_profile(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['up'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'foo' in service_names
assert len(containers) == 1
def test_profiles_up_with_profile(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['--profile', 'test', 'up'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'foo' in service_names
assert 'bar' in service_names
assert 'baz' in service_names
assert len(containers) == 3
def test_profiles_up_invalid_dependency(self):
self.base_dir = 'tests/fixtures/profiles'
result = self.dispatch(['--profile', 'debug', 'up'], returncode=1)
assert ('Service "bar" was pulled in as a dependency of service "zot" '
'but is not enabled by the active profiles.') in result.stderr
def test_profiles_up_with_multiple_profiles(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['--profile', 'debug', '--profile', 'test', 'up'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'foo' in service_names
assert 'bar' in service_names
assert 'baz' in service_names
assert 'zot' in service_names
assert len(containers) == 4
def test_profiles_up_with_profile_enabled_by_service(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['up', 'bar'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'bar' in service_names
assert len(containers) == 1
def test_profiles_up_with_dependency_and_profile_enabled_by_service(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['up', 'baz'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'bar' in service_names
assert 'baz' in service_names
assert len(containers) == 2
def test_profiles_up_with_invalid_dependency_for_target_service(self):
self.base_dir = 'tests/fixtures/profiles'
result = self.dispatch(['up', 'zot'], returncode=1)
assert ('Service "bar" was pulled in as a dependency of service "zot" '
'but is not enabled by the active profiles.') in result.stderr
def test_profiles_up_with_profile_for_dependency(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['--profile', 'test', 'up', 'zot'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'bar' in service_names
assert 'zot' in service_names
assert len(containers) == 2
def test_profiles_up_with_merged_profiles(self):
self.base_dir = 'tests/fixtures/profiles'
self.dispatch(['-f', 'docker-compose.yml', '-f', 'merge-profiles.yml', 'up', 'zot'])
containers = self.project.containers(stopped=True)
service_names = [c.service for c in containers]
assert 'bar' in service_names
assert 'zot' in service_names
assert len(containers) == 2
def test_exec_without_tty(self):
self.base_dir = 'tests/fixtures/links-composefile'
self.dispatch(['up', '-d', 'console'])
@@ -3034,3 +3143,12 @@ services:
another = self.project.get_service('--log-service')
assert len(service.containers()) == 1
assert len(another.containers()) == 1
def test_up_no_log_prefix(self):
self.base_dir = 'tests/fixtures/echo-services'
result = self.dispatch(['up', '--no-log-prefix'])
assert 'simple' in result.stdout
assert 'another' in result.stdout
assert 'exited with code 0' in result.stdout
assert 'exited with code 0' in result.stdout

View File

@@ -0,0 +1,15 @@
version: '3.8'
services:
frontend:
image: frontend
profiles: ["frontend", "gui"]
phpmyadmin:
image: phpmyadmin
depends_on:
- db
profiles:
- debug
backend:
image: backend
db:
image: mysql

1
tests/fixtures/env-file-override/.env vendored Normal file
View File

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

View File

@@ -0,0 +1,20 @@
version: "3"
services:
foo:
image: busybox:1.31.0-uclibc
bar:
image: busybox:1.31.0-uclibc
profiles:
- test
baz:
image: busybox:1.31.0-uclibc
depends_on:
- bar
profiles:
- test
zot:
image: busybox:1.31.0-uclibc
depends_on:
- bar
profiles:
- debug

View File

@@ -0,0 +1,5 @@
version: "3"
services:
bar:
profiles:
- debug

View File

@@ -1,5 +1,6 @@
import tempfile
import pytest
from ddt import data
from ddt import ddt
@@ -8,6 +9,7 @@ from ..acceptance.cli_test import dispatch
from compose.cli.command import get_project
from compose.cli.command import project_from_options
from compose.config.environment import Environment
from compose.config.errors import EnvFileNotFound
from tests.integration.testcases import DockerClientTestCase
@@ -55,13 +57,36 @@ services:
class EnvironmentOverrideFileTest(DockerClientTestCase):
def test_env_file_override(self):
base_dir = 'tests/fixtures/env-file-override'
# '--env-file' are relative to the current working dir
env = Environment.from_env_file(base_dir, base_dir+'/.env.override')
dispatch(base_dir, ['--env-file', '.env.override', 'up'])
project = get_project(project_dir=base_dir,
config_path=['docker-compose.yml'],
environment=Environment.from_env_file(base_dir, '.env.override'),
environment=env,
override_dir=base_dir)
containers = project.containers(stopped=True)
assert len(containers) == 1
assert "WHEREAMI=override" in containers[0].get('Config.Env')
assert "DEFAULT_CONF_LOADED=true" in containers[0].get('Config.Env')
dispatch(base_dir, ['--env-file', '.env.override', 'down'], None)
def test_env_file_not_found_error(self):
base_dir = 'tests/fixtures/env-file-override'
with pytest.raises(EnvFileNotFound) as excinfo:
Environment.from_env_file(base_dir, '.env.override')
assert "Couldn't find env file" in excinfo.exconly()
def test_dot_env_file(self):
base_dir = 'tests/fixtures/env-file-override'
# '.env' is relative to the project_dir (base_dir)
env = Environment.from_env_file(base_dir, None)
dispatch(base_dir, ['up'])
project = get_project(project_dir=base_dir,
config_path=['docker-compose.yml'],
environment=env,
override_dir=base_dir)
containers = project.containers(stopped=True)
assert len(containers) == 1
assert "WHEREAMI=default" in containers[0].get('Config.Env')
dispatch(base_dir, ['down'], None)

View File

@@ -0,0 +1,125 @@
import logging
import os
import socket
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from threading import Thread
import requests
from docker.transport import UnixHTTPAdapter
from tests.acceptance.cli_test import dispatch
from tests.integration.testcases import DockerClientTestCase
TEST_SOCKET_FILE = '/tmp/test-metrics-docker-cli.sock'
class MetricsTest(DockerClientTestCase):
test_session = requests.sessions.Session()
test_env = None
base_dir = 'tests/fixtures/v3-full'
@classmethod
def setUpClass(cls):
super().setUpClass()
MetricsTest.test_session.mount("http+unix://", UnixHTTPAdapter(TEST_SOCKET_FILE))
MetricsTest.test_env = os.environ.copy()
MetricsTest.test_env['METRICS_SOCKET_FILE'] = TEST_SOCKET_FILE
MetricsServer().start()
@classmethod
def test_metrics_help(cls):
# root `docker-compose` command is considered as a `--help`
dispatch(cls.base_dir, [], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose --help", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['help', 'run'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose help", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['--help'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose --help", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['run', '--help'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose --help run", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['up', '--help', 'extra_args'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose --help up", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
@classmethod
def test_metrics_simple_commands(cls):
dispatch(cls.base_dir, ['ps'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose ps", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['version'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose version", "context": "moby", ' \
b'"source": "docker-compose", "status": "success"}'
dispatch(cls.base_dir, ['version', '--yyy'], env=MetricsTest.test_env)
assert cls.get_content() == \
b'{"command": "compose version", "context": "moby", ' \
b'"source": "docker-compose", "status": "failure"}'
@staticmethod
def get_content():
resp = MetricsTest.test_session.get("http+unix://localhost")
print(resp.content)
return resp.content
def start_server(uri=TEST_SOCKET_FILE):
try:
os.remove(uri)
except OSError:
pass
httpd = HTTPServer(uri, MetricsHTTPRequestHandler, False)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(TEST_SOCKET_FILE)
sock.listen(0)
httpd.socket = sock
print('Serving on ', uri)
httpd.serve_forever()
sock.shutdown(socket.SHUT_RDWR)
sock.close()
os.remove(uri)
class MetricsServer:
@classmethod
def start(cls):
t = Thread(target=start_server, daemon=True)
t.start()
class MetricsHTTPRequestHandler(BaseHTTPRequestHandler):
usages = []
def do_GET(self):
self.client_address = ('',) # avoid exception in BaseHTTPServer.py log_message()
self.send_response(200)
self.end_headers()
for u in MetricsHTTPRequestHandler.usages:
self.wfile.write(u)
MetricsHTTPRequestHandler.usages = []
def do_POST(self):
self.client_address = ('',) # avoid exception in BaseHTTPServer.py log_message()
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
print(body)
MetricsHTTPRequestHandler.usages.append(body)
self.send_response(200)
self.end_headers()
if __name__ == '__main__':
logging.getLogger("urllib3").propagate = False
logging.getLogger("requests").propagate = False
start_server()

View File

@@ -25,6 +25,7 @@ from compose.const import COMPOSE_SPEC as VERSION
from compose.const import LABEL_PROJECT
from compose.const import LABEL_SERVICE
from compose.container import Container
from compose.errors import CompletedUnsuccessfully
from compose.errors import HealthCheckFailed
from compose.errors import NoHealthCheckConfigured
from compose.project import Project
@@ -37,6 +38,7 @@ from tests.integration.testcases import no_cluster
def build_config(**kwargs):
return config.Config(
config_version=kwargs.get('version', VERSION),
version=kwargs.get('version', VERSION),
services=kwargs.get('services'),
volumes=kwargs.get('volumes'),
@@ -1898,6 +1900,106 @@ class ProjectTest(DockerClientTestCase):
with pytest.raises(NoHealthCheckConfigured):
svc1.is_healthy()
def test_project_up_completed_successfully_dependency(self):
config_dict = {
'version': '2.1',
'services': {
'svc1': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'true'
},
'svc2': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'top',
'depends_on': {
'svc1': {'condition': 'service_completed_successfully'},
}
}
}
}
config_data = load_config(config_dict)
project = Project.from_config(
name='composetest', config_data=config_data, client=self.client
)
project.up()
svc1 = project.get_service('svc1')
svc2 = project.get_service('svc2')
assert 'svc1' in svc2.get_dependency_names()
assert svc2.containers()[0].is_running
assert len(svc1.containers()) == 0
assert svc1.is_completed_successfully()
def test_project_up_completed_unsuccessfully_dependency(self):
config_dict = {
'version': '2.1',
'services': {
'svc1': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'false'
},
'svc2': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'top',
'depends_on': {
'svc1': {'condition': 'service_completed_successfully'},
}
}
}
}
config_data = load_config(config_dict)
project = Project.from_config(
name='composetest', config_data=config_data, client=self.client
)
with pytest.raises(ProjectError):
project.up()
svc1 = project.get_service('svc1')
svc2 = project.get_service('svc2')
assert 'svc1' in svc2.get_dependency_names()
assert len(svc2.containers()) == 0
with pytest.raises(CompletedUnsuccessfully):
svc1.is_completed_successfully()
def test_project_up_completed_differently_dependencies(self):
config_dict = {
'version': '2.1',
'services': {
'svc1': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'true'
},
'svc2': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'false'
},
'svc3': {
'image': BUSYBOX_IMAGE_WITH_TAG,
'command': 'top',
'depends_on': {
'svc1': {'condition': 'service_completed_successfully'},
'svc2': {'condition': 'service_completed_successfully'},
}
}
}
}
config_data = load_config(config_dict)
project = Project.from_config(
name='composetest', config_data=config_data, client=self.client
)
with pytest.raises(ProjectError):
project.up()
svc1 = project.get_service('svc1')
svc2 = project.get_service('svc2')
svc3 = project.get_service('svc3')
assert ['svc1', 'svc2'] == svc3.get_dependency_names()
assert svc1.is_completed_successfully()
assert len(svc3.containers()) == 0
with pytest.raises(CompletedUnsuccessfully):
svc2.is_completed_successfully()
def test_project_up_seccomp_profile(self):
seccomp_data = {
'defaultAction': 'SCMP_ACT_ALLOW',

View File

@@ -948,7 +948,12 @@ class ServiceTest(DockerClientTestCase):
with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f:
f.write("FROM busybox\n")
service = self.create_service('web', build={'context': base_dir})
service = self.create_service('web',
build={'context': base_dir},
environment={
'COMPOSE_DOCKER_CLI_BUILD': '0',
'DOCKER_BUILDKIT': '0',
})
service.build()
self.addCleanup(self.client.remove_image, service.image_name)
@@ -964,7 +969,6 @@ class ServiceTest(DockerClientTestCase):
service = self.create_service('web',
build={'context': base_dir},
environment={
'COMPOSE_DOCKER_CLI_BUILD': '1',
'DOCKER_BUILDKIT': '1',
})
service.build(cli=True)
@@ -1015,7 +1019,6 @@ class ServiceTest(DockerClientTestCase):
web = self.create_service('web',
build={'context': base_dir},
environment={
'COMPOSE_DOCKER_CLI_BUILD': '1',
'DOCKER_BUILDKIT': '1',
})
project = Project('composetest', [web], self.client)

View File

@@ -61,6 +61,7 @@ class DockerClientTestCase(unittest.TestCase):
@classmethod
def tearDownClass(cls):
cls.client.close()
del cls.client
def tearDown(self):

View File

@@ -0,0 +1,56 @@
import os
import pytest
from compose.cli.colors import AnsiMode
from tests import mock
@pytest.fixture
def tty_stream():
stream = mock.Mock()
stream.isatty.return_value = True
return stream
@pytest.fixture
def non_tty_stream():
stream = mock.Mock()
stream.isatty.return_value = False
return stream
class TestAnsiModeTestCase:
@mock.patch.dict(os.environ)
def test_ansi_mode_never(self, tty_stream, non_tty_stream):
if "CLICOLOR" in os.environ:
del os.environ["CLICOLOR"]
assert not AnsiMode.NEVER.use_ansi_codes(tty_stream)
assert not AnsiMode.NEVER.use_ansi_codes(non_tty_stream)
os.environ["CLICOLOR"] = "0"
assert not AnsiMode.NEVER.use_ansi_codes(tty_stream)
assert not AnsiMode.NEVER.use_ansi_codes(non_tty_stream)
@mock.patch.dict(os.environ)
def test_ansi_mode_always(self, tty_stream, non_tty_stream):
if "CLICOLOR" in os.environ:
del os.environ["CLICOLOR"]
assert AnsiMode.ALWAYS.use_ansi_codes(tty_stream)
assert AnsiMode.ALWAYS.use_ansi_codes(non_tty_stream)
os.environ["CLICOLOR"] = "0"
assert AnsiMode.ALWAYS.use_ansi_codes(tty_stream)
assert AnsiMode.ALWAYS.use_ansi_codes(non_tty_stream)
@mock.patch.dict(os.environ)
def test_ansi_mode_auto(self, tty_stream, non_tty_stream):
if "CLICOLOR" in os.environ:
del os.environ["CLICOLOR"]
assert AnsiMode.AUTO.use_ansi_codes(tty_stream)
assert not AnsiMode.AUTO.use_ansi_codes(non_tty_stream)
os.environ["CLICOLOR"] = "0"
assert not AnsiMode.AUTO.use_ansi_codes(tty_stream)
assert not AnsiMode.AUTO.use_ansi_codes(non_tty_stream)

View File

@@ -14,49 +14,41 @@ class TestGetConfigPathFromOptions:
paths = ['one.yml', 'two.yml']
opts = {'--file': paths}
environment = Environment.from_env_file('.')
assert get_config_path_from_options('.', opts, environment) == paths
assert get_config_path_from_options(opts, environment) == paths
def test_single_path_from_env(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml'
environment = Environment.from_env_file('.')
assert get_config_path_from_options('.', {}, environment) == ['one.yml']
assert get_config_path_from_options({}, environment) == ['one.yml']
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix separator')
def test_multiple_path_from_env(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml:two.yml'
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', {}, environment
) == ['one.yml', 'two.yml']
assert get_config_path_from_options({}, environment) == ['one.yml', 'two.yml']
@pytest.mark.skipif(not IS_WINDOWS_PLATFORM, reason='windows separator')
def test_multiple_path_from_env_windows(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml;two.yml'
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', {}, environment
) == ['one.yml', 'two.yml']
assert get_config_path_from_options({}, environment) == ['one.yml', 'two.yml']
def test_multiple_path_from_env_custom_separator(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_PATH_SEPARATOR'] = '^'
os.environ['COMPOSE_FILE'] = 'c:\\one.yml^.\\semi;colon.yml'
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', {}, environment
) == ['c:\\one.yml', '.\\semi;colon.yml']
assert get_config_path_from_options({}, environment) == ['c:\\one.yml', '.\\semi;colon.yml']
def test_no_path(self):
environment = Environment.from_env_file('.')
assert not get_config_path_from_options('.', {}, environment)
assert not get_config_path_from_options({}, environment)
def test_unicode_path_from_options(self):
paths = [b'\xe5\xb0\xb1\xe5\x90\x83\xe9\xa5\xad/docker-compose.yml']
opts = {'--file': paths}
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', opts, environment
) == ['就吃饭/docker-compose.yml']
assert get_config_path_from_options(opts, environment) == ['就吃饭/docker-compose.yml']

View File

@@ -8,7 +8,6 @@ from docker.errors import APIError
from compose.cli.log_printer import build_log_generator
from compose.cli.log_printer import build_log_presenters
from compose.cli.log_printer import build_no_log_generator
from compose.cli.log_printer import consume_queue
from compose.cli.log_printer import QueueItem
from compose.cli.log_printer import wait_on_exit
@@ -75,14 +74,6 @@ def test_wait_on_exit_raises():
assert expected in wait_on_exit(mock_container)
def test_build_no_log_generator(mock_container):
mock_container.has_api_logs = False
mock_container.log_driver = 'none'
output, = build_no_log_generator(mock_container, None)
assert "WARNING: no logs are available with the 'none' log driver\n" in output
assert "exited with code" not in output
class TestBuildLogGenerator:
def test_no_log_stream(self, mock_container):

View File

@@ -137,21 +137,20 @@ class TestCLIMainTestCase:
class TestSetupConsoleHandlerTestCase:
def test_with_tty_verbose(self, logging_handler):
def test_with_console_formatter_verbose(self, logging_handler):
setup_console_handler(logging_handler, True)
assert type(logging_handler.formatter) == ConsoleWarningFormatter
assert '%(name)s' in logging_handler.formatter._fmt
assert '%(funcName)s' in logging_handler.formatter._fmt
def test_with_tty_not_verbose(self, logging_handler):
def test_with_console_formatter_not_verbose(self, logging_handler):
setup_console_handler(logging_handler, False)
assert type(logging_handler.formatter) == ConsoleWarningFormatter
assert '%(name)s' not in logging_handler.formatter._fmt
assert '%(funcName)s' not in logging_handler.formatter._fmt
def test_with_not_a_tty(self, logging_handler):
logging_handler.stream.isatty.return_value = False
setup_console_handler(logging_handler, False)
def test_without_console_formatter(self, logging_handler):
setup_console_handler(logging_handler, False, use_console_formatter=False)
assert type(logging_handler.formatter) == logging.Formatter

View File

@@ -168,12 +168,14 @@ class ConfigTest(unittest.TestCase):
}
})
)
assert cfg.config_version == VERSION
assert cfg.version == VERSION
for version in ['2', '2.0', '2.1', '2.2', '2.3',
'3', '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8']:
cfg = config.load(build_config_details({'version': version}))
assert cfg.version == version
assert cfg.config_version == version
assert cfg.version == VERSION
def test_v1_file_version(self):
cfg = config.load(build_config_details({'web': {'image': 'busybox'}}))
@@ -236,7 +238,9 @@ class ConfigTest(unittest.TestCase):
)
)
assert 'Invalid top-level property "web"' in excinfo.exconly()
assert "compose.config.errors.ConfigurationError: " \
"The Compose file 'filename.yml' is invalid because:\n" \
"'web' does not match any of the regexes: '^x-'" in excinfo.exconly()
assert VERSION_EXPLANATION in excinfo.exconly()
def test_named_volume_config_empty(self):
@@ -665,7 +669,7 @@ class ConfigTest(unittest.TestCase):
assert 'Invalid service name \'mong\\o\'' in excinfo.exconly()
def test_config_duplicate_cache_from_values_validation_error(self):
def test_config_duplicate_cache_from_values_no_validation_error(self):
with pytest.raises(ConfigurationError) as exc:
config.load(
build_config_details({
@@ -677,7 +681,7 @@ class ConfigTest(unittest.TestCase):
})
)
assert 'build.cache_from contains non-unique items' in exc.exconly()
assert 'build.cache_from contains non-unique items' not in exc.exconly()
def test_load_with_multiple_files_v1(self):
base_file = config.ConfigFile(
@@ -2393,7 +2397,8 @@ web:
'image': 'busybox',
'depends_on': {
'app1': {'condition': 'service_started'},
'app2': {'condition': 'service_healthy'}
'app2': {'condition': 'service_healthy'},
'app3': {'condition': 'service_completed_successfully'}
}
}
override = {}
@@ -2405,11 +2410,12 @@ web:
'image': 'busybox',
'depends_on': {
'app1': {'condition': 'service_started'},
'app2': {'condition': 'service_healthy'}
'app2': {'condition': 'service_healthy'},
'app3': {'condition': 'service_completed_successfully'}
}
}
override = {
'depends_on': ['app3']
'depends_on': ['app4']
}
actual = config.merge_service_dicts(base, override, VERSION)
@@ -2418,7 +2424,8 @@ web:
'depends_on': {
'app1': {'condition': 'service_started'},
'app2': {'condition': 'service_healthy'},
'app3': {'condition': 'service_started'}
'app3': {'condition': 'service_completed_successfully'},
'app4': {'condition': 'service_started'},
}
}
@@ -3563,9 +3570,11 @@ class InterpolationTest(unittest.TestCase):
@mock.patch.dict(os.environ)
def test_config_file_with_options_environment_file(self):
project_dir = 'tests/fixtures/default-env-file'
# env-file is relative to current working dir
env = Environment.from_env_file(project_dir, project_dir + '/.env2')
service_dicts = config.load(
config.find(
project_dir, None, Environment.from_env_file(project_dir, '.env2')
project_dir, None, env
)
).services
@@ -5229,6 +5238,8 @@ class GetDefaultConfigFilesTestCase(unittest.TestCase):
files = [
'docker-compose.yml',
'docker-compose.yaml',
'compose.yml',
'compose.yaml',
]
def test_get_config_path_default_file_in_basedir(self):
@@ -5262,8 +5273,10 @@ def get_config_filename_for_files(filenames, subdir=None):
base_dir = tempfile.mkdtemp(dir=project_dir)
else:
base_dir = project_dir
filename, = config.get_default_config_files(base_dir)
return os.path.basename(filename)
filenames = config.get_default_config_files(base_dir)
if not filenames:
raise config.ComposeFileNotFound(config.SUPPORTED_FILENAMES)
return os.path.basename(filenames[0])
finally:
shutil.rmtree(project_dir)
@@ -5369,7 +5382,7 @@ class SerializeTest(unittest.TestCase):
assert serialized_config['secrets']['two'] == {'external': True, 'name': 'two'}
def test_serialize_ports(self):
config_dict = config.Config(version=VERSION, services=[
config_dict = config.Config(config_version=VERSION, version=VERSION, services=[
{
'ports': [types.ServicePort('80', '8080', None, None, None)],
'image': 'alpine',
@@ -5380,8 +5393,20 @@ class SerializeTest(unittest.TestCase):
serialized_config = yaml.safe_load(serialize_config(config_dict))
assert [{'published': 8080, 'target': 80}] == serialized_config['services']['web']['ports']
def test_serialize_ports_v1(self):
config_dict = config.Config(config_version=V1, version=V1, services=[
{
'ports': [types.ServicePort('80', '8080', None, None, None)],
'image': 'alpine',
'name': 'web'
}
], volumes={}, networks={}, secrets={}, configs={})
serialized_config = yaml.safe_load(serialize_config(config_dict))
assert ['8080:80/tcp'] == serialized_config['services']['web']['ports']
def test_serialize_ports_with_ext_ip(self):
config_dict = config.Config(version=VERSION, services=[
config_dict = config.Config(config_version=VERSION, version=VERSION, services=[
{
'ports': [types.ServicePort('80', '8080', None, None, '127.0.0.1')],
'image': 'alpine',

View File

@@ -416,7 +416,7 @@ def test_interpolate_mandatory_no_err_msg(defaults_interpolator):
with pytest.raises(UnsetRequiredSubstitution) as e:
defaults_interpolator("not ok ${BAZ?}")
assert e.value.err == ''
assert e.value.err == 'BAZ'
def test_interpolate_mixed_separators(defaults_interpolator):

View File

@@ -221,34 +221,6 @@ class ContainerTest(unittest.TestCase):
container = Container(None, self.container_dict, has_been_inspected=True)
assert container.short_id == self.container_id[:12]
def test_has_api_logs(self):
container_dict = {
'HostConfig': {
'LogConfig': {
'Type': 'json-file'
}
}
}
container = Container(None, container_dict, has_been_inspected=True)
assert container.has_api_logs is True
container_dict['HostConfig']['LogConfig']['Type'] = 'none'
container = Container(None, container_dict, has_been_inspected=True)
assert container.has_api_logs is False
container_dict['HostConfig']['LogConfig']['Type'] = 'syslog'
container = Container(None, container_dict, has_been_inspected=True)
assert container.has_api_logs is False
container_dict['HostConfig']['LogConfig']['Type'] = 'journald'
container = Container(None, container_dict, has_been_inspected=True)
assert container.has_api_logs is True
container_dict['HostConfig']['LogConfig']['Type'] = 'foobar'
container = Container(None, container_dict, has_been_inspected=True)
assert container.has_api_logs is False
class GetContainerNameTestCase(unittest.TestCase):

View File

View File

@@ -0,0 +1,36 @@
import unittest
from compose.metrics.client import MetricsCommand
from compose.metrics.client import Status
class MetricsTest(unittest.TestCase):
@classmethod
def test_metrics(cls):
assert MetricsCommand('up', 'moby').to_map() == {
'command': 'compose up',
'context': 'moby',
'status': 'success',
'source': 'docker-compose',
}
assert MetricsCommand('down', 'local').to_map() == {
'command': 'compose down',
'context': 'local',
'status': 'success',
'source': 'docker-compose',
}
assert MetricsCommand('help', 'aci', Status.FAILURE).to_map() == {
'command': 'compose help',
'context': 'aci',
'status': 'failure',
'source': 'docker-compose',
}
assert MetricsCommand('run', 'ecs').to_map() == {
'command': 'compose run',
'context': 'ecs',
'status': 'success',
'source': 'docker-compose',
}

View File

@@ -3,6 +3,7 @@ from threading import Lock
from docker.errors import APIError
from compose.cli.colors import AnsiMode
from compose.parallel import GlobalLimit
from compose.parallel import parallel_execute
from compose.parallel import parallel_execute_iter
@@ -156,7 +157,7 @@ def test_parallel_execute_alignment(capsys):
def test_parallel_execute_ansi(capsys):
ParallelStreamWriter.instance = None
ParallelStreamWriter.set_noansi(value=False)
ParallelStreamWriter.set_default_ansi_mode(AnsiMode.ALWAYS)
results, errors = parallel_execute(
objects=["something", "something more"],
func=lambda x: x,
@@ -172,7 +173,7 @@ def test_parallel_execute_ansi(capsys):
def test_parallel_execute_noansi(capsys):
ParallelStreamWriter.instance = None
ParallelStreamWriter.set_noansi()
ParallelStreamWriter.set_default_ansi_mode(AnsiMode.NEVER)
results, errors = parallel_execute(
objects=["something", "something more"],
func=lambda x: x,

View File

@@ -28,6 +28,7 @@ from compose.service import Service
def build_config(**kwargs):
return Config(
config_version=kwargs.get('config_version', VERSION),
version=kwargs.get('version', VERSION),
services=kwargs.get('services'),
volumes=kwargs.get('volumes'),

View File

@@ -330,7 +330,7 @@ class ServiceTest(unittest.TestCase):
assert service.options['environment'] == environment
assert opts['labels'][LABEL_CONFIG_HASH] == \
'689149e6041a85f6fb4945a2146a497ed43c8a5cbd8991753d875b165f1b4de4'
'6da0f3ec0d5adf901de304bdc7e0ee44ec5dd7adb08aebc20fe0dd791d4ee5a8'
assert opts['environment'] == ['also=real']
def test_get_container_create_options_sets_affinity_with_binds(self):
@@ -700,6 +700,7 @@ class ServiceTest(unittest.TestCase):
config_dict = service.config_dict()
expected = {
'image_id': 'abcd',
'ipc_mode': None,
'options': {'image': 'example.com/foo'},
'links': [('one', 'one')],
'net': 'other',
@@ -723,6 +724,7 @@ class ServiceTest(unittest.TestCase):
config_dict = service.config_dict()
expected = {
'image_id': 'abcd',
'ipc_mode': None,
'options': {'image': 'example.com/foo'},
'links': [],
'networks': {},

View File

@@ -1,5 +1,5 @@
[tox]
envlist = py37,pre-commit
envlist = py37,py39,pre-commit
[testenv]
usedevelop=True
@@ -50,7 +50,7 @@ directory = coverage-html
[flake8]
max-line-length = 105
# Set this high for now
max-complexity = 11
max-complexity = 12
exclude = compose/packages
[pytest]