Compare commits

..

88 Commits

Author SHA1 Message Date
Ulysses Souza
5becea4ca9 "Bump 1.29.2"
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2021-05-10 07:30:43 -03:00
Ulysses Souza
3ecf001f96 Merge branch 'master' into 1.29.x 2021-05-10 07:17:42 -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
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
c34c88b217 "Bump 1.29.1"
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-13 20:36:47 +02:00
Anca Iordache
575d67618e Merge branch 'master' into 1.29.x 2021-04-13 20:22:04 +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
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
0773730525 "Bump 1.29.0"
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
2021-04-06 20:54:33 +02: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
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
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
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
31 changed files with 476 additions and 120 deletions

View File

@@ -1,6 +1,102 @@
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 advertisement for `docker compose` in the `up` command to avoid annoyance
- 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)
-------------------
@@ -8,7 +104,7 @@ Change log
### Bugs
- Fix SSH hostname parsing when it contains leading s/h, and removes the quiet option that was hiding the error (via docker-py bump to 4.4.2)
- 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
@@ -101,10 +197,7 @@ Change log
- Updates of READMEs
<<<<<<< HEAD
=======
>>>>>>> master
1.27.4 (2020-09-24)
-------------------

View File

@@ -1,5 +1,5 @@
ARG DOCKER_VERSION=19.03
ARG PYTHON_VERSION=3.7.9
ARG PYTHON_VERSION=3.7.10
ARG BUILD_ALPINE_VERSION=3.12
ARG BUILD_CENTOS_VERSION=7

8
Jenkinsfile vendored
View File

@@ -23,7 +23,7 @@ pipeline {
parallel {
stage('alpine') {
agent {
label 'ubuntu && amd64 && !zfs'
label 'ubuntu-2004 && amd64 && !zfs && cgroup1'
}
steps {
buildImage('alpine')
@@ -31,7 +31,7 @@ pipeline {
}
stage('debian') {
agent {
label 'ubuntu && amd64 && !zfs'
label 'ubuntu-2004 && amd64 && !zfs && cgroup1'
}
steps {
buildImage('debian')
@@ -87,7 +87,7 @@ 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 = "dockerpinata/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def storageDriver = sh(script: "docker info -f \'{{.Driver}}\'", returnStdout: true).trim()
@@ -99,7 +99,7 @@ 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:/code/.docker/config.json" \\
--volume="\${DOCKER_CONFIG}/config.json:/root/.docker/config.json" \\
-e "DOCKER_TLS_CERTDIR=" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\

View File

@@ -23,7 +23,7 @@ pipeline {
parallel {
stage('alpine') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildImage('alpine')
@@ -31,7 +31,7 @@ pipeline {
}
stage('debian') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildImage('debian')
@@ -41,7 +41,7 @@ pipeline {
}
stage('Test') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
// TODO use declarative 1.5.0 `matrix` once available on CI
@@ -61,7 +61,7 @@ pipeline {
}
stage('Generate Changelog') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
checkout scm
@@ -98,7 +98,7 @@ pipeline {
}
stage('linux binary') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
checkout scm
@@ -134,7 +134,7 @@ pipeline {
}
stage('alpine image') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildRuntimeImage('alpine')
@@ -142,7 +142,7 @@ pipeline {
}
stage('debian image') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
buildRuntimeImage('debian')
@@ -157,7 +157,7 @@ pipeline {
parallel {
stage('Pushing images') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
steps {
pushRuntimeImage('alpine')
@@ -166,7 +166,7 @@ pipeline {
}
stage('Creating Github Release') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
environment {
GITHUB_TOKEN = credentials('github-release-token')
@@ -198,7 +198,7 @@ pipeline {
}
stage('Publishing Python packages') {
agent {
label 'linux && docker && ubuntu-2004 && cgroup1'
label 'linux && docker && ubuntu-2004 && amd64 && cgroup1'
}
environment {
PYPIRC = credentials('pypirc-docker-dsg-cibot')
@@ -247,7 +247,7 @@ def buildImage(baseImage) {
def runTests(dockerVersion, pythonVersion, baseImage) {
return {
stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
node("linux && docker && ubuntu-2004 && cgroup1") {
node("linux && docker && ubuntu-2004 && amd64 && cgroup1") {
def scmvar = checkout(scm)
def imageName = "dockerpinata/compose:${baseImage}-${scmvar.GIT_COMMIT}"
def storageDriver = sh(script: "docker info -f \'{{.Driver}}\'", returnStdout: true).trim()
@@ -259,7 +259,7 @@ 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:/code/.docker/config.json" \\
--volume="\${DOCKER_CONFIG}/config.json:/root/.docker/config.json" \\
-e "DOCKER_TLS_CERTDIR=" \\
-e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\

View File

@@ -1 +1 @@
__version__ = '1.28.3'
__version__ = '1.29.2'

View File

@@ -23,6 +23,7 @@ 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
@@ -78,8 +79,10 @@ def main(): # noqa: C901
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):
exit_with_metrics(command, "Aborting.", status=Status.FAILURE)
exit_with_metrics(command, "Aborting.", status=Status.CANCELED)
except (UserError, NoSuchService, ConfigurationError,
ProjectError, OperationFailedError) as e:
exit_with_metrics(command, e.msg, status=Status.FAILURE)
@@ -98,7 +101,10 @@ def main(): # noqa: C901
e.service.name), status=Status.FAILURE)
except NoSuchCommand as e:
commands = "\n".join(parse_doc_section("commands:", getdoc(e.supercommand)))
exit_with_metrics(e.command, "No such command: {}\n\n{}".format(e.command, commands))
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):
exit_with_metrics(command, status=Status.FAILURE)
except SystemExit as e:
@@ -116,6 +122,10 @@ def main(): # noqa: C901
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)
@@ -128,7 +138,7 @@ def get_filtered_args(args):
def exit_with_metrics(command, log_msg=None, status=Status.SUCCESS, exit_code=1):
if log_msg:
if log_msg and command != 'exec':
if not exit_code:
log.info(log_msg)
else:
@@ -162,7 +172,8 @@ def dispatch():
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.')
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,
@@ -381,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.
@@ -400,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
@@ -1482,7 +1503,7 @@ def log_printer_from_project(
keep_prefix=True,
):
return LogPrinter(
containers,
[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,

View File

@@ -188,7 +188,7 @@
"properties": {
"condition": {
"type": "string",
"enum": ["service_started", "service_healthy"]
"enum": ["service_started", "service_healthy", "service_completed_successfully"]
}
},
"required": ["condition"]
@@ -335,7 +335,6 @@
"read_only": {"type": "boolean"},
"restart": {"type": "string"},
"runtime": {
"deprecated": true,
"type": "string"
},
"scale": {
@@ -367,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": {

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
@@ -149,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__)
@@ -304,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(
@@ -335,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]
@@ -556,8 +574,7 @@ def process_config_section(config_file, config, section, environment, interpolat
config_file.version,
config,
section,
environment
)
environment)
else:
return config

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:

View File

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

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

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

@@ -36,7 +36,7 @@ class MetricsCommand(requests.Session):
context_type=None, status=Status.SUCCESS,
source=MetricsSource.CLI, uri=None):
super().__init__()
self.command = "compose " + command if command else "compose --help"
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

View File

@@ -16,6 +16,7 @@ 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
@@ -61,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):
@@ -241,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)

View File

@@ -490,8 +490,6 @@ class Project:
log.info('%s uses an image, skipping' % service.name)
if cli:
log.info("Building with native build. Learn about native build in Compose here: "
"https://docs.docker.com/go/compose-native-build/")
if parallel_build:
log.warning("Flag '--parallel' is ignored when building with "
"COMPOSE_DOCKER_CLI_BUILD=1")
@@ -651,10 +649,6 @@ class Project:
override_options=None,
):
if cli:
log.info("Building with native build. Learn about native build in Compose here: "
"https://docs.docker.com/go/compose-native-build/")
self.initialize()
if not ignore_orphans:
self.find_orphan_containers(remove_orphans)

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
@@ -112,6 +112,7 @@ HOST_CONFIG_KEYS = [
CONDITION_STARTED = 'service_started'
CONDITION_HEALTHY = 'service_healthy'
CONDITION_COMPLETED_SUCCESSFULLY = 'service_completed_successfully'
class BuildError(Exception):
@@ -712,6 +713,7 @@ 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': [
@@ -753,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.
@@ -1103,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,
@@ -1125,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)
@@ -1304,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:
@@ -1790,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
@@ -1852,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()
@@ -1873,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

@@ -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" ) )
}
@@ -172,6 +172,10 @@ _docker_compose_docker_compose() {
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
@@ -618,10 +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

@@ -1,5 +1,5 @@
Click==7.1.2
coverage==5.2.1
coverage==5.5
ddt==1.4.1
flake8==3.8.3
gitpython==3.1.11
@@ -7,4 +7,3 @@ mock==3.0.5
pytest==6.0.1; python_version >= '3.5'
pytest==4.6.5; python_version < '3.5'
pytest-cov==2.10.1
PyYAML==5.3.1

View File

@@ -11,9 +11,9 @@ gitdb2==4.0.2
mccabe==0.6.1
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

View File

@@ -1,10 +1,10 @@
backports.shutil_get_terminal_size==1.0.0
cached-property==1.5.1
cached-property==1.5.1; python_version < '3.8'
certifi==2020.6.20
chardet==3.0.4
colorama==0.4.3; sys_platform == 'win32'
distro==1.5.0
docker==4.4.2
docker==5.0.0
docker-pycreds==0.4.0
dockerpty==0.4.1
docopt==0.6.2
@@ -13,9 +13,9 @@ ipaddress==1.0.23
jsonschema==3.2.0
paramiko==2.7.1
PySocks==1.7.1
python-dotenv==0.14.0
python-dotenv==0.17.0
pywin32==227; sys_platform == 'win32'
PyYAML==5.3.1
PyYAML==5.4.1
requests==2.24.0
texttable==1.6.2
urllib3==1.25.10; python_version == '3.3'

View File

@@ -15,7 +15,7 @@
set -e
VERSION="1.28.3"
VERSION="1.29.2"
IMAGE="docker/compose:$VERSION"

View File

@@ -43,7 +43,6 @@ for version in $DOCKER_VERSIONS; do
--name "$daemon_container" \
--privileged \
--volume="/var/lib/docker" \
-v $DOCKER_CONFIG/config.json:/code/.docker/config.json \
-e "DOCKER_TLS_CERTDIR=" \
"docker:$version-dind" \
dockerd -H tcp://0.0.0.0:2375 $DOCKER_DAEMON_ARGS \
@@ -51,6 +50,11 @@ for version in $DOCKER_VERSIONS; do
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.4.0, < 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,

View File

@@ -237,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'])

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

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

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

@@ -2397,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 = {}
@@ -2409,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)
@@ -2422,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'},
}
}
@@ -3567,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
@@ -5233,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):
@@ -5266,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)

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

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