Compare commits

..

223 Commits

Author SHA1 Message Date
Sebastiaan van Stijn
f472ce3493 Merge pull request #9940 from thaJeztah/go1.18_compat
go.mod: docker 5aac513617f072b15322b147052cbda0d451d389 / v22.06-dev
2022-10-21 21:37:27 +02:00
Sebastiaan van Stijn
533abc3b1d go.mod: docker 5aac513617f072b15322b147052cbda0d451d389 / v22.06-dev
This restores compatibility with go1.18, which was broken since commit;
c062238ea4

cmd.Environ() is new in go1.19, and not needed for this specific case.
Without this, trying to use this package in code that uses go1.18 will fail;

    builder/remotecontext/git/gitutils.go:216:23: cmd.Environ undefined (type *exec.Cmd has no field or method Environ)

Changing to use `os.Environ()` instead restores compatibility with go1.18

Full diff: f9cb47a052...5aac513617

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-10-21 20:33:34 +02:00
Guillaume Lours
e8ea3ad29f Merge pull request #9934 from glours/bump-engine-version
update docker engine API to apply fix of CVE-2022-39253
2022-10-21 16:39:46 +02:00
Guillaume Lours
197c16904a update docker engine API to apply fix of CVE-2022-39253
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-10-21 16:25:08 +02:00
Laura Brehm
b37a6c7f23 Merge pull request #9937 from docker/dependabot/go_modules/go.opentelemetry.io/otel-1.11.1
build(deps): bump go.opentelemetry.io/otel from 1.11.0 to 1.11.1
2022-10-21 13:31:08 +02:00
Laura Brehm
717ace9990 Update e2e module deps
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-21 13:14:47 +02:00
dependabot[bot]
8bdfc62785 build(deps): bump go.opentelemetry.io/otel from 1.11.0 to 1.11.1
Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.11.0...v1.11.1)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-21 09:36:57 +00:00
Laura Brehm
2978f1a0bc Merge pull request #9933 from laurazard/skip-flaky-test
Skip flaky test in CI `merge` workflow
2022-10-20 18:41:24 +02:00
Laura Brehm
dd13299ede Skip flaky test in CI
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-20 18:30:27 +02:00
Guillaume Lours
32ae036fd0 Merge pull request #9925 from glours/update-docker-dependencies
bump docker dependencies version
2022-10-18 17:47:21 +02:00
Guillaume Lours
3f0550f884 log the error object instead of the string message only
Co-authored-by: Nick Sieger <nicksieger@gmail.com>
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-10-18 17:34:16 +02:00
Guillaume Lours
18ce1f41b7 replace deprecated functions
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-10-18 16:57:53 +02:00
Guillaume Lours
3bf29d401c bump docker dependencies version
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-10-18 16:26:54 +02:00
Laura Brehm
c384905d70 Merge pull request #9926 from laurazard/fix-makefile-modules-target
Fix Makefile target `validate-go-mod`
2022-10-18 16:09:43 +02:00
Laura Brehm
7424a3d3c1 Fix Makefile target validate-go-mod to only run correct bakefile target
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-18 15:38:41 +02:00
Laura Brehm
7c0b8a4c96 Merge pull request #9912 from docker/dependabot/go_modules/go.opentelemetry.io/otel-1.11.0
build(deps): bump go.opentelemetry.io/otel from 1.10.0 to 1.11.0
2022-10-18 13:53:07 +02:00
Laura Brehm
6b7e9466c4 Update e2e module deps
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-18 13:41:47 +02:00
Ulysses Souza
a6dd996988 Merge pull request #9823 from ulyssessouza/add-codecov
Add Codecov
2022-10-17 15:56:59 +02:00
Ulysses Souza
91eae4f035 Add Codecov
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-10-17 15:32:51 +02:00
Tiago Silva
8b89721476 port: fix container name in error message (#9909)
The error message is using V1 separator hardcoded, it should be using the configured separator value.

Signed-off-by: Tiago Silva <Tiago.MB.Silva@edu.azores.gov.pt>
2022-10-13 14:47:35 -04:00
Guillaume Lours
3892e9cbc4 Merge pull request #9887 from milas/issue-template
github: switch to issue template form
2022-10-13 20:43:33 +02:00
Milas Bowman
f43a1e3ece github: add feature request template
Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-10-13 14:31:11 -04:00
Milas Bowman
fa1ae635d1 github: switch to issue template form
Migrate the existing template into the new format and streamline
it a bit.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-10-13 14:31:11 -04:00
dependabot[bot]
afc0263f5c build(deps): bump go.opentelemetry.io/otel from 1.10.0 to 1.11.0
Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.10.0...v1.11.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-13 09:33:25 +00:00
Laura Brehm
b15df818c7 Merge pull request #9908 from docker/dependabot/go_modules/github.com/spf13/cobra-1.6.0
build(deps): bump github.com/spf13/cobra from 1.5.0 to 1.6.0
2022-10-12 18:23:35 +02:00
Laura Brehm
bb002a7688 Update e2e mod dependencies
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-12 18:12:11 +02:00
dependabot[bot]
2ccd57e01a build(deps): bump github.com/spf13/cobra from 1.5.0 to 1.6.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.5.0...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-12 10:00:55 +00:00
Nick Sieger
1c14d30777 Merge pull request #9168 from KoditkarVedant/9089-add-support-to-docker-compose-push-quiet-option
Add support to push images quietly via compose cli 🤫
2022-10-11 17:05:17 -04:00
Nick Sieger
8bd487ac43 docs: update with result of make docs
Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-10-11 15:19:24 -05:00
Vedant Koditkar
1d4cb32001 Add support to push images quietly via compose cli
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-10-11 15:19:23 -05:00
Laura Brehm
19d1ab77eb Merge pull request #9905 from docker/dependabot/go_modules/gotest.tools/v3-3.4.0
build(deps): bump gotest.tools/v3 from 3.3.0 to 3.4.0
2022-10-10 15:32:42 +02:00
Laura Brehm
a01f62f5dc Bump e2e module deps
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-10-10 15:23:04 +02:00
dependabot[bot]
045f5ad758 build(deps): bump gotest.tools/v3 from 3.3.0 to 3.4.0
Bumps [gotest.tools/v3](https://github.com/gotestyourself/gotest.tools) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/gotestyourself/gotest.tools/releases)
- [Commits](https://github.com/gotestyourself/gotest.tools/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: gotest.tools/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-10 09:33:24 +00:00
Guillaume Lours
b6b58d26c1 don't fail when trying to remove an orphan container during down command
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-10-06 16:44:37 +02:00
Guillaume Lours
55b1b9976b Merge pull request #9894 from thaJeztah/bump_go_1.19.2
Update to go 1.19.2 to address CVE-2022-2879, CVE-2022-2880, CVE-2022-41715
2022-10-04 23:10:38 +02:00
Sebastiaan van Stijn
34441c8e4a Update to go 1.19.2 to address CVE-2022-2879, CVE-2022-2880, CVE-2022-41715
From the mailing list:

We have just released Go versions 1.19.2 and 1.18.7, minor point releases.

These minor releases include 3 security fixes following the security policy:

- archive/tar: unbounded memory consumption when reading headers

  Reader.Read did not set a limit on the maximum size of file headers.
  A maliciously crafted archive could cause Read to allocate unbounded
  amounts of memory, potentially causing resource exhaustion or panics.
  Reader.Read now limits the maximum size of header blocks to 1 MiB.

  Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue.

  This is CVE-2022-2879 and Go issue https://go.dev/issue/54853.

- net/http/httputil: ReverseProxy should not forward unparseable query parameters

  Requests forwarded by ReverseProxy included the raw query parameters from the
  inbound request, including unparseable parameters rejected by net/http. This
  could permit query parameter smuggling when a Go proxy forwards a parameter
  with an unparseable value.

  ReverseProxy will now sanitize the query parameters in the forwarded query
  when the outbound request's Form field is set after the ReverseProxy.Director
  function returns, indicating that the proxy has parsed the query parameters.
  Proxies which do not parse query parameters continue to forward the original
  query parameters unchanged.

  Thanks to Gal Goldstein (Security Researcher, Oxeye) and
  Daniel Abeles (Head of Research, Oxeye) for reporting this issue.

  This is CVE-2022-2880 and Go issue https://go.dev/issue/54663.

- regexp/syntax: limit memory used by parsing regexps

  The parsed regexp representation is linear in the size of the input,
  but in some cases the constant factor can be as high as 40,000,
  making relatively small regexps consume much larger amounts of memory.

  Each regexp being parsed is now limited to a 256 MB memory footprint.
  Regular expressions whose representation would use more space than that
  are now rejected. Normal use of regular expressions is unaffected.

  Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue.

  This is CVE-2022-41715 and Go issue https://go.dev/issue/55949.

View the release notes for more information: https://go.dev/doc/devel/release#go1.19.2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-10-04 21:27:06 +02:00
Guillaume Lours
139a6945cb Merge pull request #9886 from milas/ci-docs-repo
ci: update docs repo path
2022-09-29 19:20:49 +02:00
Milas Bowman
97a9d02dda ci: update docs repo path
The Docker docs now live at `docker/docs` instead of
`docker/docker.github.io`.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-29 13:09:25 -04:00
Laura Brehm
25c4bcef85 Merge pull request #9824 from laurazard/cucumber-test
🥒 Cucumber PoC 🥒
2022-09-27 23:38:44 +02:00
Laura Brehm
4607dac19c Adjust modules sync validating script
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 15:47:00 +02:00
Milas Bowman
616777eb4a deps: fix race condition during graph traversal (#9878)
Keep track of visited nodes to prevent visiting a service multiple
times. This is possible when a service depends on multiple others,
as an attempt could be made to visit it from multiple parents.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-27 09:01:13 -04:00
Laura Brehm
c1f475d7bd Add validate-modules target to CI matrix
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:36:15 +02:00
Laura Brehm
c6109b2e5c Add Makefile, buildx target to ensure root and e2e go.mod are kept in sync
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:35:57 +02:00
Laura Brehm
fffe7fff57 Create new e2e module to separate out test dependencies, move cucumber tests
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:52 +02:00
Laura Brehm
0a5f4e62e4 Removed tests that were replaced by Cucumber features
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:52 +02:00
Laura Brehm
d88f6805e7 Update go.mod replace
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:52 +02:00
Laura Brehm
266ab22d53 Rename start cucumber feature
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:51 +02:00
Laura Brehm
a7476c8eeb Convert cascade_stop_test.go into a cucumber feature stop.feature
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:51 +02:00
Laura Brehm
15ebff00b1 Cucumber test setup/fixtures
(run with `go test -v -run ^TestCucumberFeatures$ github.com/docker/compose/v2/pkg/e2e/cucumber`)

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-27 02:13:47 +02:00
Alex
f44ca01fcf ci: limit job permissions from default (#9874)
Signed-off-by: Alex <aleksandrosansan@gmail.com>
2022-09-26 15:41:24 -04:00
Guillaume Lours
19a1454c2d Merge pull request #9868 from bkielbasa/v2
add more information when `service.platform` isn't part of `service.build.platforms`
2022-09-26 21:12:45 +02:00
Bartłomiej Klimczak
aa297a9969 remove unnecessary code
Signed-off-by: Bartłomiej Klimczak <bartlomiej.klimczak88@gmail.com>
2022-09-26 20:54:33 +02:00
Bartłomiej Klimczak
0d0a02cc6b add more information when service.platform isn't part of service.build.platforms
Signed-off-by: Bartłomiej Klimczak <bartlomiej.klimczak88@gmail.com>
2022-09-26 20:44:59 +02:00
Guillaume Lours
3c641ed265 Merge pull request #9876 from milas/compose-go-1.6.0
ci: upgrade to compose-go v1.6.0
2022-09-26 19:42:19 +02:00
Milas Bowman
f41eec4e09 ci: upgrade to compose-go v1.6.0
https://github.com/compose-spec/compose-go/releases/tag/v1.6.0

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-26 19:23:30 +02:00
Ulysses Souza
140dc519d3 cli: add shell completion function (#9269)
Integrates PR #9462 with additional fixes/changes.

Additional changes will be required to utilize this.

Co-authored-by: Nicolas De Loof <nicolas.deloof@gmail.com>
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-09-26 13:21:45 -04:00
Guillaume Lours
279225896a run: clean service command if entrypoint is overridden (#9836)
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-26 12:08:14 -04:00
Milas Bowman
a95cc4074a Remove support for DOCKER_HOST in .env files (#9871)
Revert "Merge pull request #9817 from ulyssessouza/apply-newly-loaded-envvars"

This reverts commit 126cb988c6, reversing
changes made to b80222fb07.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-26 09:26:01 -04:00
Guillaume Lours
b4420c372b Merge pull request #9866 from glours/issue-service-platform-on-up
keep the platform defined, in priority, via DOCKER_DEFAULT_PLATFORM o…
2022-09-26 10:32:43 +02:00
Guillaume Lours
ce3700d334 keep the platform defined, in priority, via DOCKER_DEFAULT_PLATFORM or the service.plaform one if no build platforms provided
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-22 13:46:24 +02:00
Guillaume Lours
e2a3fe9427 Merge pull request #9862 from glours/use-docker-export-if-no-build-platforms
configure default builder export when no build.platforms defined
2022-09-22 13:46:00 +02:00
Laura Brehm
94465d57cc Merge pull request #9863 from docker/gha-win-mac-runners
Add `merge` GitHub Actions workflow to run tests on Windows and macOS runners
2022-09-21 16:39:27 +02:00
Laura Brehm
0dc64723c9 Restore -s in uname OS detection logic in Makefile
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-21 10:19:00 -04:00
Laura Brehm
8891d9e2b5 Streamline GHA workflow
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-21 08:59:09 -04:00
Laura Brehm
6cd68a4bf2 Upgrade actions/setup-go to v3
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:31 -04:00
Laura Brehm
a1984ca1de Skip some tests in CI due to flakiness
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:31 -04:00
Laura Brehm
118b4f07e5 Increase E2E test timeouts to reduce flakiness
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:31 -04:00
Laura Brehm
8714f983ac Temporarily disable broken E2E tests on Windows
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:31 -04:00
Laura Brehm
6bc50cb457 Rework Makefile for better Windows support
Fixes error when attempting to run `uname` on Windows, and add `.exe` to built binary on `make` if on Windows

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:31 -04:00
Laura Brehm
937fa2dc8f Add GitHub Action workflow to run tests on Mac/Windows runners
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-20 11:33:28 -04:00
Guillaume Lours
71ab6c9eef configure default builder export when no build.platforms defined
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-20 15:27:41 +02:00
Guillaume Lours
db88241698 Merge pull request #9854 from glours/fix-docker-default-platform--without-build-platform
keep the platform defined via DOCKER_DEFAULT_PLATFORM during build if no build platforms provided
2022-09-20 10:00:10 +02:00
Laura Brehm
723078c593 Remove /rebase GitHub Action since it's no longer necessary
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-19 17:50:41 -04:00
Guillaume Lours
a1c50ef2c9 keep the platform defined via DOCKER_DEFAULT_PLATFORM during build if no build platforms provided
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-16 22:19:31 +02:00
Laura Brehm
2977f4c897 Merge pull request #9849 from laurazard/fix-volumesfrom-overwriting
Keep `depends_on` condition when service has `volumes_from`
2022-09-15 10:45:48 -04:00
Laura Brehm
cfdec21a7f Fix linting issues
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-15 10:04:06 -04:00
Laura Brehm
b564cc5a17 Don't overwrite existing dependency condition
(when service has `volumes_from` another service with dependency condition)

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-15 09:53:52 -04:00
Laura Brehm
43c444e890 Add unit tests for PrepareVolumes
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-15 09:53:14 -04:00
Guillaume Lours
b25a66bbd7 Merge pull request #9847 from glours/fix-service-platform--without-build-platform
keep the platform defined at service level during build if no build patforms provided
2022-09-15 10:49:42 +02:00
Guillaume Lours
0e975262da keep the platform defined at service level during build if no build platforms provided
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-15 08:30:52 +02:00
Guillaume Lours
c4d79e60b6 Merge pull request #9840 from glours/bump-compose-go-v1.5.1
update compose-go version to v1.5.1
2022-09-14 11:45:30 +02:00
Guillaume Lours
ddc4896b10 update compose-go version to v1.5.1
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-14 11:02:58 +02:00
Guillaume Lours
9b863549ee Merge pull request #9819 from milas/down-image-rm
build: label built images for reliable cleanup on `down`
2022-09-14 10:52:45 +02:00
Milas Bowman
801678686c add license to file
Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-13 18:29:42 +01:00
Milas Bowman
403d691abf small cleanup + godoc
Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-13 18:29:33 +01:00
Milas Bowman
b49b9ffe7e Merge remote-tracking branch 'upstream/v2' into down-image-rm 2022-09-13 18:00:41 +01:00
Milas Bowman
680763f8b7 down: refactor image pruning
Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-13 17:23:44 +01:00
Guillaume Lours
1ed37ef7bd Merge pull request #9812 from milas/go-1.19.1
ci: upgrade to Go 1.19.1
2022-09-13 17:29:34 +02:00
Milas Bowman
42169db166 Merge remote-tracking branch 'upstream/v2' into go-1.19.1 2022-09-13 14:46:15 +01:00
Risky Feryansyah
d05f5f5fa7 pull: improve output for services with both image+build (#9829)
When an image pull fails but the service has a `build` section, it
will be built, so it's not an unrecoverable error. It's now logged as
a warning - in situations where the image will _never_ exist in a
registry, `pull_policy: never` can & should be used, which will
prevent the error and avoid unnecessary pull attempts.

Signed-off-by: Risky Feryansyah Pribadi <riskypribadi24@gmail.com>
2022-09-13 14:38:13 +01:00
Guillaume Lours
5cc2c27abb Merge pull request #9828 from Taha-Chaudhry/v2
Update README.md
2022-09-13 15:31:33 +02:00
Guillaume Lours
7b7189fe00 Merge pull request #9835 from docker/dependabot/go_modules/go.opentelemetry.io/otel-1.10.0
build(deps): bump go.opentelemetry.io/otel from 1.9.0 to 1.10.0
2022-09-13 11:53:45 +02:00
dependabot[bot]
de1d969c37 build(deps): bump go.opentelemetry.io/otel from 1.9.0 to 1.10.0
Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.9.0 to 1.10.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.9.0...v1.10.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-13 09:42:35 +00:00
dependabot[bot]
ab984d91af build(deps): bump github.com/AlecAivazis/survey/v2 from 2.3.5 to 2.3.6 (#9830)
Bumps [github.com/AlecAivazis/survey/v2](https://github.com/AlecAivazis/survey) from 2.3.5 to 2.3.6.
- [Release notes](https://github.com/AlecAivazis/survey/releases)
- [Commits](https://github.com/AlecAivazis/survey/compare/v2.3.5...v2.3.6)

---
updated-dependencies:
- dependency-name: github.com/AlecAivazis/survey/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-13 10:27:14 +01:00
Taha-Chaudhry
e413c2137a Update README.md
Grammar corrections

Signed-off-by: Taha-Chaudhry <46199675+Taha-Chaudhry@users.noreply.github.com>
2022-09-11 17:28:35 +03:00
Milas Bowman
61845dd781 logs: filter to services from current Compose file (#9811)
* logs: filter to services from current Compose file

When using the file model, only attach to services
referenced in the active Compose file.

For example, let's say you have `compose-base.yaml`
and `compose.yaml`, where the former only has a
subset of the services but are both run as part of
the same named project.

Project based command:
```
docker compose -p myproj logs
```
This should return logs for active services based
on the project name, regardless of Compose file
state on disk.

File based command:
```
docker compose --file compose-base.yaml logs
```
This should return logs for ONLY services that are
defined in `compose-base.yaml`. Any other services
are considered 'orphaned' within the context of the
command and should be ignored.

See also #9705.

Fixes #9801.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-08 16:26:00 -04:00
Lucas Berg
7a8d157871 convert: do not escape $ into $$ when using the --no-interpolate option (#9703)
Signed-off-by: Lucas Berg <root.lucasberg@gmail.com>
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
Co-authored-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-09-08 16:25:23 -04:00
Laura Brehm
88df5ede42 Merge pull request #9797 from laurazard/start-only-services
Only attempt to start specified services on `compose start [services]`
2022-09-08 13:00:20 -04:00
Laura Brehm
a7cc406187 Cleanup E2E tests
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-08 12:49:42 -04:00
Ulysses Souza
126cb988c6 Merge pull request #9817 from ulyssessouza/apply-newly-loaded-envvars
Apply newly loaded envvars to "DockerCli" and "APIClient"
2022-09-08 18:35:51 +02:00
Laura Brehm
4c474fe029 Add unit tests to graph building logic in dependencies.go
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-08 12:32:04 -04:00
Laura Brehm
209293e449 Restrict compose project to selected services and dependencies on compose start
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-08 12:31:55 -04:00
Ulysses Souza
79af3cdd85 Apply newly loaded envvars to "DockerCli" and "APIClient"
Re-evaluate DockerCli and APIClient after reading the environment file.
I can contain DOCKER_HOST and/or DOCKER_CONTEXT so the DockerCli passed by docker/cli has to be re-evaluated.
Also checks for DOCKER_CERT_PATH and DOCKER_TLS_VERIFY.

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-09-08 18:23:18 +02:00
Guillaume Lours
b80222fb07 Merge pull request #9821 from docker/dependabot/go_modules/go.opentelemetry.io/otel-1.9.0
build(deps): bump go.opentelemetry.io/otel from 1.4.1 to 1.9.0
2022-09-08 13:40:37 +02:00
dependabot[bot]
ff53411d9d build(deps): bump go.opentelemetry.io/otel from 1.4.1 to 1.9.0
Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.4.1 to 1.9.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.4.1...v1.9.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-08 10:09:55 +00:00
Guillaume Lours
0ac0e29294 Merge pull request #9729 from glours/add-platforms-build
Add platforms build
2022-09-08 11:42:16 +02:00
Milas Bowman
bc806da712 build: label built images for reliable cleanup on down
When running `compose down`, the `--rmi` flag can be passed,
which currently supports two values:
 * `local`: remove any _implicitly-named_ images that Compose
            built
 * `all`  : remove any named images (locally-built or fetched
            from a remote repo)

Removing images in the `local` case can be problematic, as it's
historically been done via a fair amount of inference over the
Compose model. Additionally, when using the "project-model"
(by passing `--project-name` instead of using a Compose file),
we're even more limited: if no containers for the project are
running, there's nothing to derive state from to perform the
inference on.

As a first pass, we started labeling _containers_ with the name
of the locally-built image associated with it (if any) in #9715.
Unfortunately, this still suffers from the aforementioned problems
around using actual state (i.e. the containers might no longer
exist) and meant that when operating in file mode (the default),
things did not behave as expected: the label is not available
in the project since it only exists at runtime.

Now, with these changes, Compose will label any images it builds
with project metadata. Upon cleanup during `down`, the engine
image API is queried for related images and matched up with the
services for the project. As a fallback for images built with
prior versions of Compose, the previous approach is still taken.

See also:
 * https://github.com/docker/compose/issues/9655
 * https://github.com/docker/compose/pull/9715

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-07 17:57:29 -04:00
Milas Bowman
f72a604cbd ci: upgrade golangci-lint
Need a compatible version for 1.19

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-06 17:59:11 -04:00
Milas Bowman
e81168197a ci: upgrade to Go 1.19.1
Go released 1.18.6 + 1.19.1 today which fix a couple
CVEs. (`golang.org/x/net` also has a related fix.)

This jumps from 1.18.5 -> 1.19.1 since it was on the
to-do list regardless :)

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-09-06 17:46:07 -04:00
Laura Brehm
361194472e Cleanup E2E tests
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-09-06 20:28:35 +02:00
Guillaume Lours
e7b488bb94 Merge pull request #9810 from RiskyFeryansyahP/patch-nil-custom-label
patch: build.go access custom labels directly cause panic
2022-09-06 17:59:03 +02:00
Risky Feryansyah Pribadi
07eb8a598d patch: build.go access custom labels directly cause panic
Signed-off-by: Risky Feryansyah Pribadi <riskypribadi24@gmail.com>
2022-09-06 22:46:55 +07:00
Guillaume Lours
8a9eae3190 Merge pull request #9809 from docker/dependabot/go_modules/github.com/cnabio/cnab-to-oci-0.3.7
build(deps): bump github.com/cnabio/cnab-to-oci from 0.3.6 to 0.3.7
2022-09-06 11:39:25 +02:00
dependabot[bot]
48744dbe47 build(deps): bump github.com/cnabio/cnab-to-oci from 0.3.6 to 0.3.7
Bumps [github.com/cnabio/cnab-to-oci](https://github.com/cnabio/cnab-to-oci) from 0.3.6 to 0.3.7.
- [Release notes](https://github.com/cnabio/cnab-to-oci/releases)
- [Commits](https://github.com/cnabio/cnab-to-oci/compare/v0.3.6...v0.3.7)

---
updated-dependencies:
- dependency-name: github.com/cnabio/cnab-to-oci
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-06 09:27:51 +00:00
Guillaume Lours
44c55e89c0 always use 'docker' export entry when building with 'up' or 'run' commands
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-02 15:44:55 +02:00
Guillaume Lours
e016faac33 don't push images at the end of multi-arch build (and simplify e2e tests)
support DOCKER_DEFAULT_PLATFORM when 'compose up --build'
add tests to check behaviour when DOCKER_DEFAULT_PLATFORM is defined

Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-02 15:44:55 +02:00
Guillaume Lours
8ed2d8ad07 add a test with multiple service builds using platforms in the same compose file
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-02 15:44:55 +02:00
Guillaume Lours
537f023a3b fix panic when using 'compose up --build'
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
2022-09-02 15:44:55 +02:00
Guillaume Lours
8b1b70833e add support of platforms in build section
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-09-02 15:44:55 +02:00
Guillaume Lours
06ae6d82cb Merge pull request #9802 from docker/dependabot/go_modules/github.com/docker/go-units-0.5.0
build(deps): bump github.com/docker/go-units from 0.4.0 to 0.5.0
2022-09-01 11:40:04 +02:00
dependabot[bot]
84392d52c4 build(deps): bump github.com/docker/go-units from 0.4.0 to 0.5.0
Bumps [github.com/docker/go-units](https://github.com/docker/go-units) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/docker/go-units/releases)
- [Commits](https://github.com/docker/go-units/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: github.com/docker/go-units
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-01 09:28:50 +00:00
Abdullah Shahid Khan
c87efed6a4 api: fix typo on Push godoc (#9798)
Signed-off-by: Abdullah Shahid Khan <69131903+Sh9hid@users.noreply.github.com>
2022-08-31 11:18:25 -04:00
Ulysses Souza
36926c41c6 Merge pull request #9715 from ulyssessouza/fix-down-rmi
Fix `down` with `--rmi`
2022-08-30 17:55:42 +02:00
Milas Bowman
24bf9789a6 ci: reduce noise from dependabot on Docker deps (#9770)
There's a complex dependency situation with `docker/docker`,
`docker/cli`, and `docker/buildkit`. Upgrading them usually
needs to happen in unison to ensure compatible versions
between them, particularly because `docker/buildx` is not
1.0, so has no guarantees re: compatibility, and `docker/docker`
& `docker/cli` use CalVer rather than SemVer, so also have
different compatibility guarantees than necessarily expected
by Go tooling.

Patch versions are still considered for these to ensure we
don't miss important bugfixes.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-30 08:50:23 -04:00
Laura Brehm
cc4f194295 Add E2E tests for starting/stopping single services
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-30 12:55:51 +02:00
Ulysses Souza
55cf579e02 Fix down with --rmi
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-08-29 19:48:23 +02:00
Laura Brehm
1a7c1dfe7d Merge pull request #9794 from laurazard/fix-exitcode-stop-event
Correctly capture exit code when service has dependencies
2022-08-29 16:26:30 +02:00
Laura Brehm
8301dc8314 Only capture exit codes from exit events
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-28 21:01:40 +02:00
Laura Brehm
0d2beddf20 Add E2E tests for up --exit-code-from
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-27 17:44:08 +02:00
CrazyMax
69651136cf Makefile: mutualize local and Dockerfile build opts (#9776)
Ensure that everything works nicely for `docker-ce-packaging`
as well as local development.

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-26 16:06:24 -04:00
Milas Bowman
f3e0c386d2 Revert "Apply newly loaded envvars to DockerCli and APIClient" (#9792)
Revert "Merge pull request #9745 from ulyssessouza/apply-newly-loaded-envvars"

This reverts commit 6fe34c45ca, reversing
changes made to 10cfd551e3.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-26 16:03:45 -04:00
Nick Sieger
88406491c9 Merge pull request #9786 from nicksieger/individual-checksums
ci: bring back individual checksum files
2022-08-24 09:39:09 -05:00
Nick Sieger
63b126622d ci: bring back individual checksum files
Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-08-24 09:26:56 -05:00
dependabot[bot]
23deefd20c build(deps): bump github.com/moby/buildkit from 0.10.3 to 0.10.4 (#9780)
Bumps [github.com/moby/buildkit](https://github.com/moby/buildkit) from 0.10.3 to 0.10.4.
- [Release notes](https://github.com/moby/buildkit/releases)
- [Commits](https://github.com/moby/buildkit/compare/v0.10.3...v0.10.4)

---
updated-dependencies:
- dependency-name: github.com/moby/buildkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-23 11:50:52 -04:00
Laura Brehm
e5eb00f618 Merge pull request #9781 from laurazard/pull-image-latest
Pull image regardless of whether it exists locally if `tag=latest`
2022-08-23 17:49:41 +02:00
Nick Sieger
2f2460b40e Merge pull request #9784 from nicksieger/fix-release-checksums
ci: fix checksums checking
2022-08-23 10:19:18 -05:00
Nick Sieger
3aceaa1694 Merge pull request #9783 from mikesir87/9782-remove-confusing-error-output
Remove error message showing exit code when using --exit-code-from
2022-08-23 10:13:37 -05:00
Nick Sieger
c07de59a98 ci: fix checksums checking
Create checksums.txt in a different directory so it doesn't affect the check.

Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-08-23 10:05:54 -05:00
Laura Brehm
235734823e Pull image regardless of whether it exists locally if tag=latest
... and pull policy is `missing` or `if_not_present`

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-23 16:57:40 +02:00
Michael Irwin
d23c261c7d Remove error message showing exit code when using --exit-code-from
Signed-off-by: Michael Irwin <mikesir87@gmail.com>

Resolves #9782
2022-08-23 10:47:54 -04:00
Nick Sieger
157d38aa69 Merge pull request #9777 from nicksieger/compose-9773-pull-always
pull: always pull when policy not specified
2022-08-22 13:10:14 -05:00
Nick Sieger
5723dee316 pull: only skip pull when policy is missing/if_not_present
Fixes #9773.

Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-08-22 09:22:20 -05:00
Ulysses Souza
6eb34031f6 Merge pull request #9769 from ulyssessouza/wakeup
Wake up!
2022-08-19 17:27:48 +02:00
Ulysses Souza
9e7ae6cb30 Wake up!
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-08-19 17:18:28 +02:00
Laura Brehm
f880b4129c Merge pull request #9173 from KoditkarVedant/8768-avoid-pulling-same-image-multiple-times
Avoid pulling same images multiple times 
2022-08-19 16:28:55 +02:00
Laura Brehm
832eee0e8f Merge pull request #9764 from laurazard/apply-model-kill
Apply compose model on `compose kill`, add `--remove-orphans`
2022-08-19 16:15:45 +02:00
Vedant Koditkar
a1d19119d2 Fix breaking test
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-19 15:25:22 +05:30
Vedant Koditkar
b96b5449e5 Merge branch 'v2' into 8768-avoid-pulling-same-image-multiple-times 2022-08-19 13:08:36 +05:30
Laura Brehm
a226fe9daf Update docs for new compose kill --remove-orphans option
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-19 04:29:51 +02:00
Laura Brehm
fcfcc1524e Apply compose model on compose kill, add --remove-orphans
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-19 04:26:08 +02:00
Ulysses Souza
6fe34c45ca Merge pull request #9745 from ulyssessouza/apply-newly-loaded-envvars
Apply newly loaded envvars to "DockerCli" and "APIClient"
2022-08-18 22:49:21 +02:00
Ulysses Souza
10cfd551e3 Merge pull request #9761 from ulyssessouza/refactor-osenv-precedence
Give environment variables precedence back to OS over .env
2022-08-18 22:48:36 +02:00
Ulysses Souza
0b4cb85c84 Code formatting
Just moving it up to make clearer

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-08-18 22:41:02 +02:00
Ulysses Souza
3f4f4e5975 Give environment variables precedence back to OS over .env
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-08-18 22:39:21 +02:00
Ulysses Souza
86c925fbd3 Reset the DockerCli and APIClient after loading the environment file
This forces a re-evaluation of the environment variables.

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
2022-08-18 16:42:56 +02:00
Nick Sieger
a64a5a61a7 Merge pull request #9759 from nicksieger/issue-9591
Don't wait for disabled dependency
2022-08-17 13:21:12 -05:00
Nick Sieger
09e6b0292a up/start/run: don't wait for disabled service
Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-08-17 12:32:10 -05:00
Nick Sieger
3c561e7017 create: pull all services logic out of loop; add DependsOn deps
Signed-off-by: Nick Sieger <nick@nicksieger.com>
2022-08-17 11:48:45 -05:00
dependabot[bot]
8ad63f7150 build(deps): bump github.com/mattn/go-isatty from 0.0.14 to 0.0.16 (#9754)
Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.14 to 0.0.16.
- [Release notes](https://github.com/mattn/go-isatty/releases)
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.14...v0.0.16)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-isatty
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-17 09:57:13 -04:00
Guillaume Lours
10532201a2 Merge pull request #9751 from crazy-max/new-archs
build windows/arm64 and linux/riscv64 binaries
2022-08-15 09:32:52 +02:00
CrazyMax
3022b6479f build windows/arm64 and linux/riscv64 binaries
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-15 09:24:14 +02:00
Guillaume Lours
abc73ed3d6 Merge pull request #9750 from crazy-max/fix-checksums
ci: fix checksums file
2022-08-15 09:23:50 +02:00
CrazyMax
0ec04058cd ci: fix checksums file
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-14 22:29:57 +02:00
Vedant Koditkar
293cf21c58 Merge branch '8768-avoid-pulling-same-image-multiple-times' of github.com:KoditkarVedant/compose into 8768-avoid-pulling-same-image-multiple-times 2022-08-14 16:52:17 +05:30
Vedant Koditkar
25f4cb2ee6 Use compose to pull image twice
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-14 16:51:29 +05:30
Vedant Koditkar
817e875cbf Merge branch 'v2' into 8768-avoid-pulling-same-image-multiple-times 2022-08-13 12:19:49 +05:30
Guillaume Lours
8d12042f39 Merge pull request #9748 from crazy-max/log-filter
root: filter out commandConn.Close* warning message
2022-08-13 07:33:42 +02:00
CrazyMax
f5a1bb875d root: filter out commandConn.Close* warning message
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-12 23:49:02 +02:00
Guillaume Lours
3e5b8659eb Merge pull request #9747 from crazy-max/fix-readme
readme: fix badges
2022-08-12 23:39:55 +02:00
Vedant Koditkar
79ed1290a6 Use alpine:3.13.12 to be unique across the test cases
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-13 02:59:44 +05:30
CrazyMax
51ef754387 readme: fix badges
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-12 23:29:13 +02:00
Guillaume Lours
58c477f916 Merge pull request #9744 from crazy-max/cross
Better sandboxed workflow and enhanced cross compilation
2022-08-12 22:38:14 +02:00
Vedant Koditkar
4853ace155 Fix package name
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-13 02:06:28 +05:30
Vedant Koditkar
de49bea774 Try changing package used to avoid any race condition in tests
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-12 23:06:51 +05:30
CrazyMax
5ec20296e4 Better sandboxed workflow and enhanced cross compilation
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-08-12 15:05:58 +02:00
Guillaume Lours
e8389306ae Merge pull request #9736 from docker/dependabot/go_modules/github.com/containerd/containerd-1.6.8
build(deps): bump github.com/containerd/containerd from 1.6.7 to 1.6.8
2022-08-11 00:09:33 +02:00
dependabot[bot]
3fc020c20a build(deps): bump github.com/containerd/containerd from 1.6.7 to 1.6.8
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.6.7 to 1.6.8.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.6.7...v1.6.8)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-10 23:57:37 +02:00
Vedant Koditkar
0db6dfee03 make compose pull tests more expressive
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-08-10 21:48:27 +05:30
Milas Bowman
27227a8824 lint: add nolintlint and clean up nolint directives (#9738)
Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-09 16:43:58 -04:00
Milas Bowman
12ad0fddab lint: run gofmt from Go 1.19 (#9728)
Fix comment formatting.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-08 11:36:57 -04:00
Vedant Koditkar
e623b5ca1e Merge branch 'v2' into 8768-avoid-pulling-same-image-multiple-times 2022-08-06 17:58:10 +05:30
Guillaume Lours
359133b800 Merge pull request #9720 from glours/respect-pull-policy-build
don't apply default pull policy from command line if one is define in service configuration
2022-08-05 16:50:24 +02:00
Guillaume Lours
c47079e795 don't apply default pull policy from command line if one is define in service configuration
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-08-05 12:01:32 +02:00
Guillaume Lours
bf4ca6219a Merge pull request #9721 from glours/update-docker-cli
update Docker CLI version use in CI to v20.10.17
2022-08-05 12:00:51 +02:00
Guillaume Lours
ae08f57928 Merge pull request #9723 from docker/dependabot/go_modules/github.com/containerd/containerd-1.6.7
build(deps): bump github.com/containerd/containerd from 1.6.6 to 1.6.7
2022-08-05 11:37:29 +02:00
dependabot[bot]
ca990146e9 build(deps): bump github.com/containerd/containerd from 1.6.6 to 1.6.7
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.6.6 to 1.6.7.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.6.6...v1.6.7)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-05 09:27:47 +00:00
Guillaume Lours
143a40a618 update Docker CLI version use in CI to v20.10.17
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-08-05 10:46:36 +02:00
Guillaume Lours
7c405706b4 Merge pull request #9722 from glours/fix-linting-ci-task
fix version of golangci-lint to v1.47.3, issue with v1.48.0 for now
2022-08-05 10:46:21 +02:00
Guillaume Lours
e65ada3984 fix version of golangci-lint to v1.47.3, issue with v1.48.0 for now
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-08-05 10:37:11 +02:00
Laura Brehm
bb04677b0f Merge pull request #9714 from docker/dependabot/go_modules/github.com/cnabio/cnab-to-oci-0.3.6
build(deps): bump github.com/cnabio/cnab-to-oci from 0.3.5 to 0.3.6
2022-08-04 13:17:35 +02:00
dependabot[bot]
7572bec674 build(deps): bump github.com/cnabio/cnab-to-oci from 0.3.5 to 0.3.6
Bumps [github.com/cnabio/cnab-to-oci](https://github.com/cnabio/cnab-to-oci) from 0.3.5 to 0.3.6.
- [Release notes](https://github.com/cnabio/cnab-to-oci/releases)
- [Commits](https://github.com/cnabio/cnab-to-oci/compare/v0.3.5...v0.3.6)

---
updated-dependencies:
- dependency-name: github.com/cnabio/cnab-to-oci
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 09:34:56 +00:00
Milas Bowman
1ee44a0acb config: use correct YAML marshal func (#9712)
The `compose-spec/compose-go` lib is written with `gopkg.in/yaml.v2`
as a target.

When marshalling via CLI (`compose convert` / `compose config`), we
were using a _different_ YAML lib, which was a fork of `go-yaml`,
which is what `gopkg.in/yaml.v2` is based off of.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-03 20:41:43 +00:00
Khoa Le
8d4846f210 docs: remove extra whitespaces in help text (#9710)
Remove superfluous whitespaces

Signed-off-by: Khoa Le <ltkhoa2711@gmail.com>
2022-08-03 16:37:15 -04:00
Sebastiaan van Stijn
92f32b5c79 ci: use latest stable dockerfile syntax & rename docs Dockerfile (#9711)
* update dockerfiles to use latest stable syntax

Some Dockerfiles were pinned to a minor release, which meant they
wouldn't be updated to get the latest stable syntax (and fixes),
and one Dockerfile used the "labs" variant to use the HEREDOC syntax,
which has now been promoted to the stable syntax.

* docs: rename Dockerfile

There's no other Dockerfiles in the same path, so the "docs"
prefix was redundant.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-08-03 16:36:13 -04:00
Laura Brehm
ca05ffe36e Merge pull request #9375 from ndeloof/project_or_name
if command is ran with a compose file, apply the compose model
2022-08-03 18:47:49 +02:00
Laura Brehm
c586ca4d0e Change projectOrName() to check COMPOSE_PROJECT_NAME env var
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-03 18:39:39 +02:00
Laura Brehm
be495ab8e6 Filter compose ps output by provided compose model
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-02 22:33:26 +02:00
Laura Brehm
d2a6c2c200 Add E2E tests for compose stop with compose file
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-02 22:33:26 +02:00
Nicolas De Loof
f6e96dd783 if command is ran with a compose file, apply the compose model, not just project name
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
2022-08-02 22:33:26 +02:00
Milas Bowman
765c071c89 up: do not stop dependency containers (#9701)
This keeps parity with v1, where only the containers explicitly
passed to `up` are torn down when `Ctrl-C` is hit, so any
dependencies that got launched (or orphan containers hanging
around) should not be touched.

Fixes #9696.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-02 15:25:59 -04:00
Guillaume Lours
3dfdad61df Merge pull request #9709 from milas/bump-deps
build: upgrade BuildKit & docker/distribution
2022-08-02 21:02:02 +02:00
ikedam
bbaaa6a9de config: case-insensitive env vars on Windows (#9438)
Signed-off-by: IKEDA Yasuyuki <devld@ikedam.jp>
2022-08-02 14:56:09 -04:00
Milas Bowman
ddd9d4b6e4 build: upgrade BuildKit & docker/distribution
Housekeeping - bumping dependencies to latest version
available.

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-02 14:52:08 -04:00
Guillaume Lours
d0d06d414d Merge pull request #9708 from milas/golang-1.18.5
build: bump to Go 1.18.5
2022-08-02 19:49:15 +02:00
Milas Bowman
b1e4cde2da build: bump to Go 1.18.5
Can give 1.19 a bit of time before we upgrade ;)

Signed-off-by: Milas Bowman <milas.bowman@docker.com>
2022-08-02 13:40:37 -04:00
Guillaume Lours
9e48afb830 Merge pull request #9706 from thaJeztah/improve_usage_consistency
update usage strings for consistency
2022-08-02 17:54:49 +02:00
Sebastiaan van Stijn
9db79856be update usage strings for consistency
This updates the format of various usage strings to be more consistent
with other parts of the CLI.

- Use `[OPTIONS]` to indicate where command-specific options should be added
- Use `[SERVICE...]` to indicate zero-or-more services
- Remove some usage strings for specific options (e.g. `-e NAME=VAL`), as that
  option is part of the already mentioned `[OPTIONS]` and we don't provide usage
  for each possible option that can be passed.
- Remove `[--]`, which (I think) was needed for the Python implementation, but is
  a general feature to stop processing flag-options.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-08-02 13:32:29 +02:00
Laura Brehm
5ead5d1cd6 Merge pull request #9689 from glours/remove-close-workflow
remove unused workflows, especially the pr-closed which always failed
2022-08-02 11:38:00 +02:00
Guillaume Lours
7289e87a38 Merge pull request #9700 from glours/bump-compose-go-1.4.0
update to compose-go v1.4.0 as previous version introduced breaking changes
2022-08-01 17:57:02 +02:00
Guillaume Lours
052469104f switch tests back to '_' separator for networks and volumes
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-08-01 17:25:43 +02:00
Guillaume Lours
bff44ff466 update to compose-go v1.4.0 as previous version introduced breaking changes
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-08-01 16:57:57 +02:00
Laura Brehm
57f98eff03 Merge pull request #9692 from floatingstatic/linklocal
Fix LinkLocalIPs in V2
2022-08-01 16:11:00 +02:00
Guillaume Lours
1eeb12fe1e Merge pull request #9698 from laurazard/dont-load-composefile-version
Overwrite parent commands PreRun code for `compose version`
2022-08-01 12:14:14 +02:00
Laura Brehm
c9876f4c66 Overwrite parent commands PreRun code for compose version
.. to avoid trying (and failing) to load a compose file if the COMPOSE_FILE env var is set such as `COMPOSE_FILE=foo compose version`

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2022-08-01 11:44:05 +02:00
Guillaume Lours
4bd12e1aa3 Merge pull request #9639 from ikedam/linkToBuilding
Link to BUILDING.md for testing instructions
2022-07-30 11:46:38 +02:00
IKEDA Yasuyuki
d789b2e426 Improve descriptions about tests in CONTRIBUTING.md
Signed-off-by: IKEDA Yasuyuki <devld@ikedam.jp>
2022-07-30 17:18:39 +09:00
Jeremiah Millay
8d84a12333 Fix LinkLocalIPs in V2
Signed-off-by: Jeremiah Millay <jmillay@fastly.com>
2022-07-29 21:19:34 +02:00
Guillaume Lours
ce740b1ff6 remove unused workflows, especially the pr-closed which always failed
Signed-off-by: Guillaume Lours <guillaume.lours@docker.com>
2022-07-29 19:30:36 +02:00
IKEDA Yasuyuki
630c600929 Link to BUILDING.md for testing instructions
Signed-off-by: IKEDA Yasuyuki <devld@ikedam.jp>
2022-07-09 12:05:22 +09:00
Vedant Koditkar
960453fa22 Merge branch 'v2' into 8768-avoid-pulling-same-image-multiple-times 2022-07-04 22:00:04 +05:30
Vedant Koditkar
e24d274bbc Fix breaking TestComposePull test case
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-03-05 23:46:08 +05:30
Vedant Koditkar
89dfb9140e Merge branch 'v2' into 8768-avoid-pulling-same-image-multiple-times 2022-03-05 21:53:55 +05:30
Vedant Koditkar
d62c9fe842 Avoid pulling same images multiple times
Signed-off-by: Vedant Koditkar <vedant.koditkar@outlook.com>
2022-02-14 17:16:48 +05:30
176 changed files with 5501 additions and 2507 deletions

View File

@@ -1,2 +1 @@
bin/
dist/

View File

@@ -1,64 +0,0 @@
<!--
If you are reporting a new issue, make sure that we do not have any duplicates
already open. You can ensure this by searching the issue list for this
repository. If there is a duplicate, please close your issue and add a comment
to the existing issue instead.
If you suspect your issue is a bug, please edit your issue description to
include the BUG REPORT INFORMATION shown below. If you fail to provide this
information within 7 days, we cannot debug your issue and will close it. We
will, however, reopen it if you later provide the information.
For more information about reporting issues, see
https://github.com/docker/compose-cli/blob/master/CONTRIBUTING.md#reporting-other-issues
---------------------------------------------------
GENERAL SUPPORT INFORMATION
---------------------------------------------------
The GitHub issue tracker is for bug reports and feature requests.
General support can be found at the following locations:
- Docker Support Forums - https://forums.docker.com
- Docker Community Slack - https://dockr.ly/slack
- Post a question on StackOverflow, using the Docker tag
---------------------------------------------------
BUG REPORT INFORMATION
---------------------------------------------------
Use the commands below to provide key information from your environment:
You do NOT have to include this information if this is a FEATURE REQUEST
-->
**Description**
<!--
Briefly describe the problem you are having in a few paragraphs.
-->
**Steps to reproduce the issue:**
1.
2.
3.
**Describe the results you received:**
**Describe the results you expected:**
**Additional information you deem important (e.g. issue happens only occasionally):**
**Output of `docker compose version`:**
```
(paste your output here)
```
**Output of `docker info`:**
```
(paste your output here)
```
**Additional environment details:**

49
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: 🐞 Bug
description: File a bug/issue
title: "[BUG] <title>"
labels: ['status/0-triage', 'kind/bug']
body:
- type: textarea
attributes:
label: Description
description: |
Briefly describe the problem you are having.
Include both the current behavior (what you are seeing) as well as what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: Compose Version
description: |
Paste output of `docker compose version` and `docker-compose version`.
render: Text
validations:
required: false
- type: textarea
attributes:
label: Docker Environment
description: Paste output of `docker info`.
render: Text
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
blank_issues_enabled: true
contact_links:
- name: Docker Community Slack
url: https://dockr.ly/slack
about: 'Use the #docker-compose channel'
- name: Docker Support Forums
url: https://forums.docker.com/c/open-source-projects/compose/15
about: 'Use the "Open Source Projects > Compose" category'
- name: 'Ask on Stack Overflow'
url: https://stackoverflow.com/questions/tagged/docker-compose
about: 'Use the [docker-compose] tag when creating new questions'

View File

@@ -0,0 +1,13 @@
name: Feature request
description: Missing functionality? Come tell us about it!
labels:
- kind/feature
- status/0-triage
body:
- type: textarea
id: description
attributes:
label: Description
description: What is the feature you want to see?
validations:
required: true

View File

@@ -4,3 +4,15 @@ updates:
directory: /
schedule:
interval: daily
ignore:
# docker/buildx + docker/cli + docker/docker require coordination to
# ensure compatibility between them
- dependency-name: "github.com/docker/buildx"
# buildx is still 0.x
update-types: ["version-update:semver-minor"]
- dependency-name: "github.com/docker/cli"
# docker/cli uses CalVer rather than SemVer
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "github.com/docker/docker"
# docker/docker uses CalVer rather than SemVer
update-types: ["version-update:semver-major", "version-update:semver-minor"]

View File

@@ -1,60 +0,0 @@
name: Publish Artifacts
env:
GO_VERSION: 1.18.4
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: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build cross platform compose-plugin binaries
run: make -f builder.Makefile cross
- name: Upload macos-amd64 binary
uses: actions/upload-artifact@v3
with:
name: docker-compose-darwin-amd64
path: ${{ github.workspace }}/bin/docker-compose-darwin-amd64
- name: Upload macos-arm64 binary
uses: actions/upload-artifact@v3
with:
name: docker-compose-darwin-arm64
path: ${{ github.workspace }}/bin/docker-compose-darwin-arm64
- name: Upload linux-amd64 binary
uses: actions/upload-artifact@v3
with:
name: docker-compose-linux-amd64
path: ${{ github.workspace }}/bin/docker-compose-linux-amd64
- name: Upload linux-ppc64le binary
uses: actions/upload-artifact@v3
with:
name: docker-compose-linux-ppc64le
path: ${{ github.workspace }}/bin/docker-compose-linux-ppc64le
- name: Upload windows-amd64 binary
uses: actions/upload-artifact@v3
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

View File

@@ -1,9 +1,15 @@
name: Continuous integration
name: ci
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- v2
- 'v2'
tags:
- 'v*'
pull_request:
workflow_dispatch:
inputs:
@@ -11,113 +17,219 @@ on:
description: 'To run with tmate enter "debug_enabled"'
required: false
default: "false"
env:
GO_VERSION: 1.18.4
DESTDIR: "./bin"
DOCKER_CLI_VERSION: "20.10.17"
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
lint:
name: Lint
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
- name: Checkout code into the Go module directory
-
name: Checkout
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Validate go-mod, license headers and docs are up-to-date
run: make validate
- name: Run golangci-lint
env:
BUILD_TAGS: e2e
uses: golangci/golangci-lint-action@v2
with:
args: --timeout=180s
# 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'
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
# 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-plugin:
name: Build and tests in plugin mode
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Setup docker CLI
-
name: Create matrix
id: platforms
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
echo ::set-output name=matrix::$(docker buildx bake binary-cross --print | jq -cr '.target."binary-cross".platforms')
-
name: Show matrix
run: |
echo ${{ steps.platforms.outputs.matrix }}
- name: Test
run: make -f builder.Makefile test
validate:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- lint
- validate-go-mod
- validate-modules
- validate-headers
- validate-docs
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Run
run: |
make ${{ matrix.target }}
- name: Build for local E2E
env:
BUILD_TAGS: e2e
run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin
binary:
runs-on: ubuntu-latest
needs:
- prepare
strategy:
fail-fast: false
matrix:
platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
-
name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Build
uses: docker/bake-action@v2
with:
targets: release
set: |
*.platform=${{ matrix.platform }}
*.cache-from=type=gha,scope=binary-${{ env.PLATFORM_PAIR }}
*.cache-to=type=gha,scope=binary-${{ env.PLATFORM_PAIR }},mode=max
-
name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: compose
path: ${{ env.DESTDIR }}/*
if-no-files-found: error
- name: E2E Test in plugin mode
run: make e2e-compose
build-standalone:
name: Build and tests in standalone mode
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Test
uses: docker/bake-action@v2
with:
targets: test
set: |
*.cache-from=type=gha,scope=test
*.cache-to=type=gha,scope=test
- name: Set up Go ${{ env.GO_VERSION }}
e2e:
runs-on: ubuntu-latest
env:
DESTDIR: "./bin/build"
strategy:
fail-fast: false
matrix:
mode:
- plugin
- standalone
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Set up Go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
go-version-file: 'go.mod'
check-latest: true
cache: true
- name: Setup docker CLI
-
name: Setup docker CLI
run: |
curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.3.tgz | tar xz
curl https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz | tar xz
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
- name: Build for local E2E
-
name: Build
uses: docker/bake-action@v2
with:
targets: binary
set: |
*.cache-from=type=gha,scope=binary-linux-amd64
*.cache-from=type=gha,scope=binary-e2e-${{ matrix.mode }}
*.cache-to=type=gha,scope=binary-e2e-${{ matrix.mode }},mode=max
env:
BUILD_TAGS: e2e
run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
-
name: Setup tmate session
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
uses: mxschmitt/action-tmate@8b4e4ac71822ed7e0ad5fb3d1c33483e9e8fb270 # v3.11
with:
limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
- name: E2E Test in standalone mode
-
name: Test plugin mode
if: ${{ matrix.mode == 'plugin' }}
run: |
make e2e-compose
-
name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
-
name: Test standalone mode
if: ${{ matrix.mode == 'standalone' }}
run: |
rm -f /usr/local/bin/docker-compose
cp bin/docker-compose /usr/local/bin
cp bin/build/docker-compose /usr/local/bin
make e2e-compose-standalone
release:
permissions:
contents: write # to create a release (ncipollo/release-action)
runs-on: ubuntu-latest
needs:
- binary
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Download artifacts
uses: actions/download-artifact@v3
with:
name: compose
path: ${{ env.DESTDIR }}
-
name: Create checksums
working-directory: ${{ env.DESTDIR }}
run: |
find . -type f -print0 | sort -z | xargs -r0 shasum -a 256 -b | sed 's# \*\./# *#' > $RUNNER_TEMP/checksums.txt
shasum -a 256 -U -c $RUNNER_TEMP/checksums.txt
mv $RUNNER_TEMP/checksums.txt .
cat checksums.txt | while read sum file; do echo "$sum $file" > ${file#\*}.sha256; done
-
name: License
run: cp packaging/* ${{ env.DESTDIR }}/
-
name: List artifacts
run: |
tree -nh ${{ env.DESTDIR }}
-
name: Check artifacts
run: |
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
-
name: GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 # v1.10.0
with:
artifacts: ${{ env.DESTDIR }}/*
generateReleaseNotes: true
draft: true
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -4,8 +4,13 @@ on:
release:
types: [published]
permissions: {}
jobs:
open-pr:
permissions:
contents: write # to create branch (peter-evans/create-pull-request)
pull-requests: write # to create a PR (peter-evans/create-pull-request)
runs-on: ubuntu-latest
steps:
-
@@ -13,7 +18,7 @@ jobs:
uses: actions/checkout@v3
with:
token: ${{ secrets.GHPAT_DOCS_DISPATCH }}
repository: docker/docker.github.io
repository: docker/docs
ref: master
-
name: Prepare

74
.github/workflows/merge.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
name: merge
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- 'v2'
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
e2e:
name: Build and test
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [desktop-windows, desktop-macos, desktop-m1]
# mode: [plugin, standalone]
mode: [plugin]
env:
GO111MODULE: "on"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version-file: go.mod
cache: true
check-latest: true
- name: List Docker resources on machine
run: |
docker ps --all
docker volume ls
docker network ls
docker image ls
- name: Remove Docker resources on machine
continue-on-error: true
run: |
docker kill $(docker ps -q)
docker rm -f $(docker ps -aq)
docker volume rm -f $(docker volume ls -q)
docker ps --all
- name: Unit tests
run: make test
- name: Build binaries
run: |
make
- name: Check arch of go compose binary
run: |
file ./bin/build/docker-compose
if: ${{ !contains(matrix.os, 'desktop-windows') }}
-
name: Test plugin mode
if: ${{ matrix.mode == 'plugin' }}
run: |
make e2e-compose
-
name: Test standalone mode
if: ${{ matrix.mode == 'standalone' }}
run: |
make e2e-compose-standalone

View File

@@ -1,11 +0,0 @@
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

View File

@@ -1,19 +0,0 @@
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@v3
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 }}

View File

@@ -1,45 +0,0 @@
name: Releaser
on:
workflow_dispatch:
inputs:
tag:
description: "Release Tag"
required: true
env:
GO_VERSION: 1.18.4
jobs:
upload-release:
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- 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: Build
run: make GIT_TAG=${{ github.event.inputs.tag }} -f builder.Makefile cross
- name: Compute checksums
run: cd bin; for f in *; do shasum --binary --algorithm 256 $f | tee -a checksums.txt > $f.sha256; done
- name: License
run: cp packaging/* bin/
- uses: ncipollo/release-action@v1
with:
artifacts: "bin/*"
generateReleaseNotes: true
draft: true
commit: "v2"
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event.inputs.tag }}

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
bin/
dist/
/.vscode/
coverage.out

View File

@@ -1,10 +1,10 @@
run:
concurrency: 2
timeout: 10m
linters:
enable-all: false
disable-all: true
enable:
- deadcode
- depguard
- errcheck
- gocritic
@@ -18,16 +18,19 @@ linters:
- lll
- misspell
- nakedret
- nolintlint
- staticcheck
- structcheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
linters-settings:
revive:
rules:
- name: package-comments
disabled: true
depguard:
list-type: blacklist
list-type: denylist
include-go-root: true
packages:
# The io/ioutil package has been deprecated.

View File

@@ -19,7 +19,8 @@ Once you have the prerequisites installed, you can build the CLI using:
make
```
This will output a `docker-compose` CLI plugin for your host machine in `./bin`.
This will output a `docker-compose` CLI plugin for your host machine in
`./bin/build`.
You can statically cross compile the CLI for Windows, macOS, and Linux using the
`cross` target.
@@ -38,7 +39,6 @@ If you need to update a golden file simply do `go test ./... -test.update-golden
To run e2e tests, the Compose CLI binary need to be build. All the commands to run e2e tests propose a version
with the prefix `build-and-e2e` to first build the CLI before executing tests.
Note that this requires a local Docker Engine to be running.
#### Whole end-to-end tests suite
@@ -76,6 +76,7 @@ make e2e-compose-standalone
```
Or if you need to build the CLI, run:
```console
make build-and-e2e-compose-standalone
```

View File

@@ -124,9 +124,10 @@ Fork the repository and make changes on your fork in a feature branch:
issue.
Submit unit tests for your changes. Go has a great test framework built in; use
it! Take a look at existing tests for inspiration. [Run the full test
suite](README.md) on your branch before
submitting a pull request.
it! Take a look at existing tests for inspiration. Also end-to-end tests are
available. Run the full test suite, both unit tests and e2e tests on your
branch before submitting a pull request. See [BUILDING.md](BUILDING.md) for
instructions to build and run tests.
Write clean code. Universally formatted code promotes ease of writing, reading,
and maintenance. Always run `gofmt -s -w file.go` on each changed file before

View File

@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.2
# syntax=docker/dockerfile:1
# Copyright 2020 Docker Compose CLI authors
@@ -15,101 +15,174 @@
# See the License for the specific language governing permissions and
# limitations under the License.
ARG GO_VERSION=1.18.4-alpine
ARG GOLANGCI_LINT_VERSION=v1.46.2-alpine
ARG PROTOC_GEN_GO_VERSION=v1.4.3
ARG GO_VERSION=1.19.2
ARG XX_VERSION=1.1.2
ARG GOLANGCI_LINT_VERSION=v1.49.0
ARG ADDLICENSE_VERSION=v1.0.0
FROM --platform=${BUILDPLATFORM} golangci/golangci-lint:${GOLANGCI_LINT_VERSION} AS local-golangci-lint
ARG BUILD_TAGS="e2e,kube"
ARG DOCS_FORMATS="md,yaml"
ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.go\|\.hcl\|\.sh\)"
FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION} AS base
WORKDIR /compose-cli
RUN apk add --no-cache -vv \
git \
docker \
make \
protoc \
protobuf-dev
# xx is a helper for cross-compilation
FROM --platform=${BUILDPLATFORM} tonistiigi/xx:${XX_VERSION} AS xx
FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
FROM ghcr.io/google/addlicense:${ADDLICENSE_VERSION} AS addlicense
FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS base
COPY --from=xx / /
RUN apk add --no-cache \
docker \
file \
git \
make \
protoc \
protobuf-dev
WORKDIR /src
ENV CGO_ENABLED=0
FROM base AS build-base
COPY go.* .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go mod download
FROM base AS lint
ENV CGO_ENABLED=0
COPY --from=local-golangci-lint /usr/bin/golangci-lint /usr/bin/golangci-lint
ARG BUILD_TAGS
ARG GIT_TAG
RUN --mount=target=. \
FROM build-base AS vendored
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/root/.cache/golangci-lint \
BUILD_TAGS=${BUILD_TAGS} \
GIT_TAG=${GIT_TAG} \
make -f builder.Makefile lint
go mod tidy && mkdir /out && cp go.mod go.sum /out
FROM base AS make-compose-plugin
ENV CGO_ENABLED=0
FROM scratch AS vendor-update
COPY --from=vendored /out /
FROM vendored AS vendor-validate
RUN --mount=type=bind,target=.,rw <<EOT
set -e
git add -A
cp -rf /out/* .
diff=$(git status --porcelain -- go.mod go.sum)
if [ -n "$diff" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "make go-mod-tidy"'
echo "$diff"
exit 1
fi
EOT
FROM vendored AS modules-validate
RUN apk add --no-cache bash
RUN apk add --no-cache jq
RUN --mount=type=bind,target=.,rw ./verify-go-modules.sh e2e
FROM build-base AS build
ARG BUILD_TAGS
ARG TARGETPLATFORM
RUN xx-go --wrap
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \
make build GO_BUILDTAGS="$BUILD_TAGS" DESTDIR=/usr/bin && \
xx-verify --static /usr/bin/docker-compose
FROM build-base AS lint
ARG BUILD_TAGS
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=from=golangci-lint,source=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \
golangci-lint run --build-tags "$BUILD_TAGS" ./...
FROM build-base AS test
ARG CGO_ENABLED=0
ARG BUILD_TAGS
RUN --mount=type=bind,target=. \
--mount=type=cache,target=/root/.cache \
--mount=type=cache,target=/go/pkg/mod \
go test -tags "$BUILD_TAGS" -v -coverprofile=/tmp/coverage.txt -covermode=atomic $(go list $(TAGS) ./... | grep -vE 'e2e') && \
go tool cover -func=/tmp/coverage.txt
FROM scratch AS test-coverage
COPY --from=test /tmp/coverage.txt /coverage.txt
FROM base AS license-set
ARG LICENSE_FILES
RUN --mount=type=bind,target=.,rw \
--mount=from=addlicense,source=/app/addlicense,target=/usr/bin/addlicense \
find . -regex "${LICENSE_FILES}" | xargs addlicense -c 'Docker Compose CLI' -l apache && \
mkdir /out && \
find . -regex "${LICENSE_FILES}" | cpio -pdm /out
FROM scratch AS license-update
COPY --from=set /out /
FROM base AS license-validate
ARG LICENSE_FILES
RUN --mount=type=bind,target=. \
--mount=from=addlicense,source=/app/addlicense,target=/usr/bin/addlicense \
find . -regex "${LICENSE_FILES}" | xargs addlicense -check -c 'Docker Compose CLI' -l apache -ignore validate -ignore testdata -ignore resolvepath -v
FROM base AS docsgen
WORKDIR /src
RUN --mount=target=. \
--mount=target=/root/.cache,type=cache \
go build -o /out/docsgen ./docs/yaml/main/generate.go
FROM --platform=${BUILDPLATFORM} alpine AS docs-build
RUN apk add --no-cache rsync git
WORKDIR /src
COPY --from=docsgen /out/docsgen /usr/bin
ARG DOCS_FORMATS
RUN --mount=target=/context \
--mount=target=.,type=tmpfs <<EOT
set -e
rsync -a /context/. .
docsgen --formats "$DOCS_FORMATS" --source "docs/reference"
mkdir /out
cp -r docs/reference /out
EOT
FROM scratch AS docs-update
COPY --from=docs-build /out /out
FROM docs-build AS docs-validate
RUN --mount=target=/context \
--mount=target=.,type=tmpfs <<EOT
set -e
rsync -a /context/. .
git add -A
rm -rf docs/reference/*
cp -rf /out/* ./docs/
if [ -n "$(git status --porcelain -- docs/reference)" ]; then
echo >&2 'ERROR: Docs result differs. Please update with "make docs"'
git status --porcelain -- docs/reference
exit 1
fi
EOT
FROM scratch AS binary-unix
COPY --link --from=build /usr/bin/docker-compose /
FROM binary-unix AS binary-darwin
FROM binary-unix AS binary-linux
FROM scratch AS binary-windows
COPY --link --from=build /usr/bin/docker-compose /docker-compose.exe
FROM binary-$TARGETOS AS binary
FROM --platform=$BUILDPLATFORM alpine AS releaser
WORKDIR /work
ARG TARGETOS
ARG TARGETARCH
ARG BUILD_TAGS
ARG GIT_TAG
RUN --mount=target=. \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
GOOS=${TARGETOS} \
GOARCH=${TARGETARCH} \
BUILD_TAGS=${BUILD_TAGS} \
GIT_TAG=${GIT_TAG} \
make COMPOSE_BINARY=/out/docker-compose -f builder.Makefile compose-plugin
ARG TARGETVARIANT
RUN --mount=from=binary \
mkdir -p /out && \
# TODO: should just use standard arch
TARGETARCH=$([ "$TARGETARCH" = "amd64" ] && echo "x86_64" || echo "$TARGETARCH"); \
TARGETARCH=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "$TARGETARCH"); \
cp docker-compose* "/out/docker-compose-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}$(ls docker-compose* | sed -e 's/^docker-compose//')"
FROM base AS make-cross
ARG BUILD_TAGS
ARG GIT_TAG
RUN --mount=target=. \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
BUILD_TAGS=${BUILD_TAGS} \
GIT_TAG=${GIT_TAG} \
make COMPOSE_BINARY=/out/docker-compose -f builder.Makefile cross
FROM scratch AS compose-plugin
COPY --from=make-compose-plugin /out/* .
FROM scratch AS cross
COPY --from=make-cross /out/* .
FROM base AS test
ENV CGO_ENABLED=0
ARG BUILD_TAGS
ARG GIT_TAG
RUN --mount=target=. \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
BUILD_TAGS=${BUILD_TAGS} \
GIT_TAG=${GIT_TAG} \
make -f builder.Makefile test
FROM base AS check-license-headers
RUN go install github.com/google/addlicense@latest
RUN --mount=target=. \
make -f builder.Makefile check-license-headers
FROM base AS make-go-mod-tidy
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go mod tidy
FROM scratch AS go-mod-tidy
COPY --from=make-go-mod-tidy /compose-cli/go.mod .
COPY --from=make-go-mod-tidy /compose-cli/go.sum .
FROM base AS check-go-mod
COPY . .
RUN make -f builder.Makefile check-go-mod
FROM scratch AS release
COPY --from=releaser /out/ /
# docs-reference is a target used as remote context to update docs on release
# with latest changes on docker.github.io.
# with latest changes on docs.docker.com.
# see open-pr job in .github/workflows/docs.yml for more details
FROM scratch AS docs-reference
COPY docs/reference/*.yaml .

View File

@@ -12,39 +12,57 @@
# See the License for the specific language governing permissions and
# limitations under the License.
export DOCKER_BUILDKIT=1
PKG := github.com/docker/compose/v2
VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
GO_LDFLAGS ?= -s -w -X ${PKG}/internal.Version=${VERSION}
GO_BUILDTAGS ?= e2e,kube
ifeq ($(OS),Windows_NT)
DETECTED_OS = Windows
else
DETECTED_OS = $(shell uname -s)
endif
ifeq ($(DETECTED_OS),Linux)
MOBY_DOCKER=/usr/bin/docker
endif
ifeq ($(UNAME_S),Darwin)
ifeq ($(DETECTED_OS),Darwin)
MOBY_DOCKER=/Applications/Docker.app/Contents/Resources/bin/docker
endif
ifeq ($(DETECTED_OS),Windows)
BINARY_EXT=.exe
endif
BINARY_FOLDER=$(shell pwd)/bin
GIT_TAG?=$(shell git describe --tags --match "v[0-9]*")
TEST_FLAGS?=
TEST_COVERAGE_FLAGS = -race -coverprofile=coverage.out -covermode=atomic
TEST_FLAGS?= -timeout 15m
E2E_TEST?=
ifeq ($(E2E_TEST),)
else
TEST_FLAGS=-run $(E2E_TEST)
endif
all: compose-plugin
BUILDX_CMD ?= docker buildx
DESTDIR ?= ./bin/build
.PHONY: compose-plugin
compose-plugin: ## Compile the compose cli-plugin
@docker build . --target compose-plugin \
--platform local \
--build-arg BUILD_TAGS=e2e,kube \
--build-arg GIT_TAG=$(GIT_TAG) \
--output ./bin
all: build
.PHONY: build ## Build the compose cli-plugin
build:
CGO_ENABLED=0 GO111MODULE=on go build -trimpath -tags "$(GO_BUILDTAGS)" -ldflags "$(GO_LDFLAGS)" -o "$(DESTDIR)/docker-compose$(BINARY_EXT)" ./cmd
.PHONY: binary
binary:
$(BUILDX_CMD) bake binary
.PHONY: install
install: binary
mkdir -p ~/.docker/cli-plugins
install bin/build/docker-compose ~/.docker/cli-plugins/docker-compose
.PHONY: e2e-compose
e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
docker compose version
go test $(TEST_FLAGS) -count=1 ./pkg/e2e
go test $(TEST_FLAGS) $(TEST_COVERAGE_FLAGS) -count=1 ./pkg/e2e
.PHONY: e2e-compose-standalone
e2e-compose-standalone: ## Run End to end local tests in standalone mode. Set E2E_TEST=TestName to run a single test
@@ -52,10 +70,10 @@ e2e-compose-standalone: ## Run End to end local tests in standalone mode. Set E2
go test $(TEST_FLAGS) -v -count=1 -parallel=1 --tags=standalone ./pkg/e2e
.PHONY: build-and-e2e-compose
build-and-e2e-compose: compose-plugin e2e-compose ## Compile the compose cli-plugin and run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
build-and-e2e-compose: build e2e-compose ## Compile the compose cli-plugin and run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
.PHONY: build-and-e2e-compose-standalone
build-and-e2e-compose-standalone: compose-plugin e2e-compose-standalone ## Compile the compose cli-plugin and run End to end local tests in standalone mode. Set E2E_TEST=TestName to run a single test
build-and-e2e-compose-standalone: build e2e-compose-standalone ## Compile the compose cli-plugin and run End to end local tests in standalone mode. Set E2E_TEST=TestName to run a single test
.PHONY: mocks
mocks:
@@ -67,49 +85,35 @@ mocks:
e2e: e2e-compose e2e-compose-standalone ## Run end to end local tests in both modes. Set E2E_TEST=TestName to run a single test
.PHONY: build-and-e2e
build-and-e2e: compose-plugin e2e-compose e2e-compose-standalone ## Compile the compose cli-plugin and run end to end local tests in both modes. Set E2E_TEST=TestName to run a single test
build-and-e2e: build e2e-compose e2e-compose-standalone ## Compile the compose cli-plugin and run end to end local tests in both modes. Set E2E_TEST=TestName to run a single test
.PHONY: cross
cross: ## Compile the CLI for linux, darwin and windows
@docker build . --target cross \
--build-arg BUILD_TAGS \
--build-arg GIT_TAG=$(GIT_TAG) \
--output ./bin \
$(BUILDX_CMD) bake binary-cross
.PHONY: test
test: ## Run unit tests
@docker build --progress=plain . \
--build-arg BUILD_TAGS=kube \
--build-arg GIT_TAG=$(GIT_TAG) \
--target test
$(BUILDX_CMD) bake test
.PHONY: cache-clear
cache-clear: ## Clear the builder cache
@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h
$(BUILDX_CMD) prune --force --filter type=exec.cachemount --filter=unused-for=24h
.PHONY: lint
lint: ## run linter(s)
@docker build . \
--build-arg BUILD_TAGS=kube,e2e \
--build-arg GIT_TAG=$(GIT_TAG) \
--target lint
$(BUILDX_CMD) bake lint
.PHONY: docs
docs: ## generate documentation
$(eval $@_TMP_OUT := $(shell mktemp -d -t dockercli-output.XXXXXXXXXX))
docker build . \
--output type=local,dest=$($@_TMP_OUT) \
-f ./docs/docs.Dockerfile \
--target update
$(eval $@_TMP_OUT := $(shell mktemp -d -t compose-output.XXXXXXXXXX))
$(BUILDX_CMD) bake --set "*.output=type=local,dest=$($@_TMP_OUT)" docs-update
rm -rf ./docs/internal
cp -R "$($@_TMP_OUT)"/out/* ./docs/
rm -rf "$($@_TMP_OUT)"/*
.PHONY: validate-docs
validate-docs: ## validate the doc does not change
@docker build . \
-f ./docs/docs.Dockerfile \
--target validate
$(BUILDX_CMD) bake docs-validate
.PHONY: check-dependencies
check-dependencies: ## check dependency updates
@@ -117,19 +121,23 @@ check-dependencies: ## check dependency updates
.PHONY: validate-headers
validate-headers: ## Check license header for all files
@docker build . --target check-license-headers
$(BUILDX_CMD) bake license-validate
.PHONY: go-mod-tidy
go-mod-tidy: ## Run go mod tidy in a container and output resulting go.mod and go.sum
@docker build . --target go-mod-tidy --output .
$(BUILDX_CMD) bake vendor-update
.PHONY: validate-go-mod
validate-go-mod: ## Validate go.mod and go.sum are up-to-date
@docker build . --target check-go-mod
$(BUILDX_CMD) bake vendor-validate
validate: validate-go-mod validate-headers validate-docs ## Validate sources
.PHONY: validate-modules
validate-modules: ## Validate root and e2e go.mod are synced
$(BUILDX_CMD) bake modules-validate
pre-commit: validate check-dependencies lint compose-plugin test e2e-compose
validate: validate-go-mod validate-modules validate-headers validate-docs ## Validate sources
pre-commit: validate check-dependencies lint build test e2e-compose
help: ## Show help
@echo Please specify a build target. The choices are:

View File

@@ -1,6 +1,10 @@
# Docker Compose v2
[![Actions Status](https://github.com/docker/compose/workflows/Continuous%20integration/badge.svg)](https://github.com/docker/compose/actions)
[![GitHub release](https://img.shields.io/github/release/docker/compose.svg?style=flat-square)](https://github.com/docker/compose/releases/latest)
[![PkgGoDev](https://img.shields.io/badge/go.dev-docs-007d9c?style=flat-square&logo=go&logoColor=white)](https://pkg.go.dev/github.com/docker/compose/v2)
[![Build Status](https://img.shields.io/github/workflow/status/docker/compose/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/compose/actions?query=workflow%3Aci)
[![Go Report Card](https://goreportcard.com/badge/github.com/docker/compose/v2?style=flat-square)](https://goreportcard.com/report/github.com/docker/compose/v2)
[![Codecov](https://codecov.io/gh/docker/compose/branch/master/graph/badge.svg?token=HP3K4Y4ctu)](https://codecov.io/gh/docker/compose)
![Docker Compose](logo.png?raw=true "Docker Compose Logo")
@@ -32,12 +36,12 @@ You can download Docker Compose binaries from the
Rename the relevant binary for your OS to `docker-compose` and copy it to `$HOME/.docker/cli-plugins`
Or copy it into one of these folders for installing it system-wide:
Or copy it into one of these folders to install it system-wide:
* `/usr/local/lib/docker/cli-plugins` OR `/usr/local/libexec/docker/cli-plugins`
* `/usr/lib/docker/cli-plugins` OR `/usr/libexec/docker/cli-plugins`
(might require to make the downloaded file executable with `chmod +x`)
(might require making the downloaded file executable with `chmod +x`)
Quick Start

View File

@@ -1,73 +0,0 @@
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
GOOS?=$(shell go env GOOS)
GOARCH?=$(shell go env GOARCH)
PKG_NAME := github.com/docker/compose/v2
EXTENSION:=
ifeq ($(GOOS),windows)
EXTENSION:=.exe
endif
STATIC_FLAGS=CGO_ENABLED=0
GIT_TAG?=$(shell git describe --tags --match "v[0-9]*")
LDFLAGS="-s -w -X $(PKG_NAME)/internal.Version=${GIT_TAG}"
GO_BUILD=$(STATIC_FLAGS) go build -trimpath -ldflags=$(LDFLAGS)
COMPOSE_BINARY?=bin/docker-compose
COMPOSE_BINARY_WITH_EXTENSION=$(COMPOSE_BINARY)$(EXTENSION)
WORK_DIR:=$(shell mktemp -d)
TAGS:=
ifdef BUILD_TAGS
TAGS=-tags $(BUILD_TAGS)
LINT_TAGS=--build-tags $(BUILD_TAGS)
endif
.PHONY: compose-plugin
compose-plugin:
GOOS=${GOOS} GOARCH=${GOARCH} $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY_WITH_EXTENSION) ./cmd
.PHONY: cross
cross:
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-x86_64 ./cmd
GOOS=linux GOARCH=ppc64le $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-ppc64le ./cmd
GOOS=linux GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-aarch64 ./cmd
GOOS=linux GOARM=6 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv6 ./cmd
GOOS=linux GOARM=7 GOARCH=arm $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-armv7 ./cmd
GOOS=linux GOARCH=s390x $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-linux-s390x ./cmd
GOOS=darwin GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-darwin-x86_64 ./cmd
GOOS=darwin GOARCH=arm64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-darwin-aarch64 ./cmd
GOOS=windows GOARCH=amd64 $(GO_BUILD) $(TAGS) -o $(COMPOSE_BINARY)-windows-x86_64.exe ./cmd
.PHONY: test
test:
go test $(TAGS) -cover $(shell go list $(TAGS) ./... | grep -vE 'e2e')
.PHONY: lint
lint:
golangci-lint run $(LINT_TAGS) --timeout 10m0s ./...
.PHONY: check-license-headers
check-license-headers:
./scripts/validate/fileheader
.PHONY: check-go-mod
check-go-mod:
./scripts/validate/check-go-mod

View File

@@ -23,6 +23,13 @@ import (
"github.com/docker/compose/v2/cmd/compose"
)
func getCompletionCommands() []string {
return []string{
"__complete",
"__completeNoDesc",
}
}
func getBoolFlags() []string {
return []string{
"--debug", "-D",
@@ -50,6 +57,10 @@ func Convert(args []string) []string {
l := len(args)
for i := 0; i < l; i++ {
arg := args[i]
if contains(getCompletionCommands(), arg) {
command = append([]string{arg}, command...)
continue
}
if len(arg) > 0 && arg[0] != '-' {
// not a top-level flag anymore, keep the rest of the command unmodified
if arg == compose.PluginName {

View File

@@ -77,7 +77,7 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "build [SERVICE...]",
Use: "build [OPTIONS] [SERVICE...]",
Short: "Build or rebuild services",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
if opts.memory != "" {
@@ -102,7 +102,7 @@ func buildCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
return runBuild(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT")
cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.")

View File

@@ -19,6 +19,7 @@ package compose
import (
"strings"
"github.com/docker/compose/v2/pkg/api"
"github.com/spf13/cobra"
)
@@ -27,11 +28,11 @@ type validArgsFn func(cmd *cobra.Command, args []string, toComplete string) ([]s
func noCompletion() validArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
return []string{}, cobra.ShellCompDirectiveNoSpace
}
}
func serviceCompletion(p *projectOptions) validArgsFn {
func completeServiceNames(p *projectOptions) validArgsFn {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
project, err := p.toProject(nil)
if err != nil {
@@ -46,3 +47,21 @@ func serviceCompletion(p *projectOptions) validArgsFn {
return serviceNames, cobra.ShellCompDirectiveNoFileComp
}
}
func completeProjectNames(backend api.Service) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
list, err := backend.List(cmd.Context(), api.ListOptions{
All: true,
})
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
var values []string
for _, stack := range list {
if strings.HasPrefix(stack.Name, toComplete) {
values = append(values, stack.Name)
}
}
return values, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@@ -28,6 +28,7 @@ import (
"github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types"
composegoutils "github.com/compose-spec/compose-go/utils"
"github.com/docker/buildx/util/logutil"
dockercli "github.com/docker/cli/cli"
"github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli/command"
@@ -136,6 +137,24 @@ func (o *projectOptions) addProjectFlags(f *pflag.FlagSet) {
_ = f.MarkHidden("workdir")
}
func (o *projectOptions) projectOrName() (*types.Project, string, error) {
name := o.ProjectName
var project *types.Project
if o.ProjectName == "" {
p, err := o.toProject(nil)
if err != nil {
envProjectName := os.Getenv("COMPOSE_PROJECT_NAME")
if envProjectName != "" {
return nil, envProjectName, nil
}
return nil, "", err
}
project = p
name = p.Name
}
return project, name, nil
}
func (o *projectOptions) toProjectName() (string, error) {
if o.ProjectName != "" {
return o.ProjectName, nil
@@ -232,6 +251,16 @@ func RunningAsStandalone() bool {
// RootCommand returns the compose command with its child commands
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
// filter out useless commandConn.CloseWrite warning message that can occur
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
logrus.AddHook(logutil.NewFilter([]logrus.Level{
logrus.WarnLevel,
},
"commandConn.CloseWrite:",
"commandConn.CloseRead:",
))
opts := projectOptions{}
var (
ansi string
@@ -329,6 +358,17 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
)
c.Flags().SetInterspersed(false)
opts.addProjectFlags(c.Flags())
c.RegisterFlagCompletionFunc( //nolint:errcheck
"project-name",
completeProjectNames(backend),
)
c.RegisterFlagCompletionFunc( //nolint:errcheck
"file",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"yaml", "yml"}, cobra.ShellCompDirectiveFilterFileExt
},
)
c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
c.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
c.Flags().MarkHidden("version") //nolint:errcheck
@@ -354,8 +394,10 @@ func setEnvWithDotEnv(prjOpts *projectOptions) error {
return err
}
for k, v := range envFromFile {
if err := os.Setenv(k, v); err != nil { // overwrite the process env with merged OS + env file results
return err
if _, ok := os.LookupEnv(k); !ok { // Precedence to OS Env
if err := os.Setenv(k, v); err != nil {
return err
}
}
}
return nil

View File

@@ -18,6 +18,7 @@ package compose
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
@@ -58,7 +59,7 @@ func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
cmd := &cobra.Command{
Aliases: []string{"config"},
Use: "convert SERVICES",
Use: "convert [OPTIONS] [SERVICE...]",
Short: "Converts the compose file to platform's canonical format",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
if opts.quiet {
@@ -92,7 +93,7 @@ func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
return runConvert(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]")
@@ -112,7 +113,7 @@ func convertCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runConvert(ctx context.Context, backend api.Service, opts convertOptions, services []string) error {
var json []byte
var content []byte
project, err := opts.toProject(services,
cli.WithInterpolation(!opts.noInterpolate),
cli.WithResolvedPaths(true),
@@ -136,7 +137,7 @@ func runConvert(ctx context.Context, backend api.Service, opts convertOptions, s
}
}
json, err = backend.Convert(ctx, project, api.ConvertOptions{
content, err = backend.Convert(ctx, project, api.ConvertOptions{
Format: opts.Format,
Output: opts.Output,
})
@@ -144,19 +145,23 @@ func runConvert(ctx context.Context, backend api.Service, opts convertOptions, s
return err
}
if !opts.noInterpolate {
content = escapeDollarSign(content)
}
if opts.quiet {
return nil
}
var out io.Writer = os.Stdout
if opts.Output != "" && len(json) > 0 {
if opts.Output != "" && len(content) > 0 {
file, err := os.Create(opts.Output)
if err != nil {
return err
}
out = bufio.NewWriter(file)
}
_, err = fmt.Fprint(out, string(json))
_, err = fmt.Fprint(out, string(content))
return err
}
@@ -237,3 +242,9 @@ func runConfigImages(opts convertOptions, services []string) error {
}
return nil
}
func escapeDollarSign(marshal []byte) []byte {
dollar := []byte{'$'}
escDollar := []byte{'$', '$'}
return bytes.ReplaceAll(marshal, dollar, escDollar)
}

View File

@@ -60,7 +60,7 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command {
opts.destination = args[1]
return runCopy(ctx, backend, opts)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := copyCmd.Flags()

View File

@@ -31,6 +31,7 @@ type createOptions struct {
Build bool
noBuild bool
Pull string
pullChanged bool
removeOrphans bool
ignoreOrphans bool
forceRecreate bool
@@ -45,9 +46,10 @@ type createOptions struct {
func createCommand(p *projectOptions, backend api.Service) *cobra.Command {
opts := createOptions{}
cmd := &cobra.Command{
Use: "create [SERVICE...]",
Use: "create [OPTIONS] [SERVICE...]",
Short: "Creates containers for a service.",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
opts.pullChanged = cmd.Flags().Changed("pull")
if opts.Build && opts.noBuild {
return fmt.Errorf("--build and --no-build are incompatible")
}
@@ -68,7 +70,7 @@ func createCommand(p *projectOptions, backend api.Service) *cobra.Command {
QuietPull: false,
})
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.")
@@ -108,7 +110,7 @@ func (opts createOptions) GetTimeout() *time.Duration {
}
func (opts createOptions) Apply(project *types.Project) {
if opts.Pull != "" {
if opts.pullChanged {
for i, service := range project.Services {
service.PullPolicy = opts.Pull
project.Services[i] = service

View File

@@ -22,7 +22,6 @@ import (
"os"
"time"
"github.com/compose-spec/compose-go/types"
"github.com/docker/compose/v2/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -45,7 +44,7 @@ func downCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
downCmd := &cobra.Command{
Use: "down",
Use: "down [OPTIONS]",
Short: "Stop and remove containers, networks",
PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
opts.timeChanged = cmd.Flags().Changed("timeout")
@@ -66,7 +65,7 @@ func downCommand(p *projectOptions, backend api.Service) *cobra.Command {
removeOrphans := utils.StringToBool(os.Getenv("COMPOSE_REMOVE_ORPHANS"))
flags.BoolVar(&opts.removeOrphans, "remove-orphans", removeOrphans, "Remove containers for services not defined in the Compose file.")
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
flags.BoolVarP(&opts.volumes, "volumes", "v", false, " Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers.")
flags.BoolVarP(&opts.volumes, "volumes", "v", false, "Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers.")
flags.StringVar(&opts.images, "rmi", "", `Remove images used by services. "local" remove only images that don't have a custom tag ("local"|"all")`)
flags.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
if name == "volume" {
@@ -79,15 +78,9 @@ func downCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runDown(ctx context.Context, backend api.Service, opts downOptions) error {
name := opts.ProjectName
var project *types.Project
if opts.ProjectName == "" {
p, err := opts.toProject(nil)
if err != nil {
return err
}
project = p
name = p.Name
project, name, err := opts.projectOrName()
if err != nil {
return err
}
var timeout *time.Duration

View File

@@ -38,12 +38,12 @@ func eventsCommand(p *projectOptions, backend api.Service) *cobra.Command {
},
}
cmd := &cobra.Command{
Use: "events [options] [--] [SERVICE...]",
Use: "events [OPTIONS] [SERVICE...]",
Short: "Receive real time events from containers.",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runEvents(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects")
@@ -51,12 +51,12 @@ func eventsCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runEvents(ctx context.Context, backend api.Service, opts eventsOpts, services []string) error {
project, err := opts.toProjectName()
name, err := opts.toProjectName()
if err != nil {
return err
}
return backend.Events(ctx, project, api.EventsOptions{
return backend.Events(ctx, name, api.EventsOptions{
Services: services,
Consumer: func(event api.Event) error {
if opts.json {

View File

@@ -50,7 +50,7 @@ func execCommand(p *projectOptions, dockerCli command.Cli, backend api.Service)
},
}
runCmd := &cobra.Command{
Use: "exec [options] [-e KEY=VAL...] [--] SERVICE COMMAND [ARGS...]",
Use: "exec [OPTIONS] SERVICE COMMAND [ARGS...]",
Short: "Execute a command in a running container.",
Args: cobra.MinimumNArgs(2),
PreRunE: Adapt(func(ctx context.Context, args []string) error {
@@ -61,7 +61,7 @@ func execCommand(p *projectOptions, dockerCli command.Cli, backend api.Service)
RunE: Adapt(func(ctx context.Context, args []string) error {
return runExec(ctx, backend, opts)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
runCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: Run command in the background.")

View File

@@ -43,12 +43,12 @@ func imagesCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
imgCmd := &cobra.Command{
Use: "images [SERVICE...]",
Use: "images [OPTIONS] [SERVICE...]",
Short: "List images used by the created containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runImages(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
return imgCmd

View File

@@ -18,15 +18,18 @@ package compose
import (
"context"
"os"
"github.com/spf13/cobra"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
)
type killOptions struct {
*projectOptions
signal string
removeOrphans bool
signal string
}
func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
@@ -34,29 +37,33 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "kill [options] [SERVICE...]",
Use: "kill [OPTIONS] [SERVICE...]",
Short: "Force stop service containers.",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runKill(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
removeOrphans := utils.StringToBool(os.Getenv("COMPOSE_REMOVE_ORPHANS"))
flags.BoolVar(&opts.removeOrphans, "remove-orphans", removeOrphans, "Remove containers for services not defined in the Compose file.")
flags.StringVarP(&opts.signal, "signal", "s", "SIGKILL", "SIGNAL to send to the container.")
return cmd
}
func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
return backend.Kill(ctx, projectName, api.KillOptions{
Services: services,
Signal: opts.signal,
return backend.Kill(ctx, name, api.KillOptions{
RemoveOrphans: opts.removeOrphans,
Project: project,
Services: services,
Signal: opts.signal,
})
}

View File

@@ -41,7 +41,7 @@ type lsOptions struct {
func listCommand(backend api.Service) *cobra.Command {
lsOpts := lsOptions{Filter: opts.NewFilterOpt()}
lsCmd := &cobra.Command{
Use: "ls",
Use: "ls [OPTIONS]",
Short: "List running compose projects",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runList(ctx, backend, lsOpts)

View File

@@ -44,12 +44,12 @@ func logsCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
logsCmd := &cobra.Command{
Use: "logs [SERVICE...]",
Use: "logs [OPTIONS] [SERVICE...]",
Short: "View output from containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runLogs(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := logsCmd.Flags()
flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output.")
@@ -63,12 +63,13 @@ func logsCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runLogs(ctx context.Context, backend api.Service, opts logsOptions, services []string) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
consumer := formatter.NewLogConsumer(ctx, os.Stdout, !opts.noColor, !opts.noPrefix)
return backend.Logs(ctx, projectName, consumer, api.LogOptions{
return backend.Logs(ctx, name, consumer, api.LogOptions{
Project: project,
Services: services,
Follow: opts.follow,
Tail: opts.tail,

View File

@@ -38,19 +38,20 @@ func pauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPause(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
return cmd
}
func runPause(ctx context.Context, backend api.Service, opts pauseOptions, services []string) error {
project, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
return backend.Pause(ctx, project, api.PauseOptions{
return backend.Pause(ctx, name, api.PauseOptions{
Services: services,
Project: project,
})
}
@@ -68,18 +69,19 @@ func unpauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runUnPause(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
return cmd
}
func runUnPause(ctx context.Context, backend api.Service, opts unpauseOptions, services []string) error {
project, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
return backend.UnPause(ctx, project, api.PauseOptions{
return backend.UnPause(ctx, name, api.PauseOptions{
Services: services,
Project: project,
})
}

View File

@@ -38,7 +38,7 @@ func portCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "port [options] [--] SERVICE PRIVATE_PORT",
Use: "port [OPTIONS] SERVICE PRIVATE_PORT",
Short: "Print the public port for a port binding.",
Args: cobra.MinimumNArgs(2),
PreRunE: Adapt(func(ctx context.Context, args []string) error {
@@ -52,7 +52,7 @@ func portCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPort(ctx, backend, opts, args[0])
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp")
cmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if service has multiple replicas")

View File

@@ -70,7 +70,7 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
psCmd := &cobra.Command{
Use: "ps [SERVICE...]",
Use: "ps [OPTIONS] [SERVICE...]",
Short: "List containers",
PreRunE: func(cmd *cobra.Command, args []string) error {
return opts.parseFilter()
@@ -78,7 +78,7 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPs(ctx, backend, args, opts)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := psCmd.Flags()
flags.StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json]")
@@ -91,11 +91,12 @@ func psCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runPs(ctx context.Context, backend api.Service, services []string, opts psOptions) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
containers, err := backend.Ps(ctx, projectName, api.PsOptions{
containers, err := backend.Ps(ctx, name, api.PsOptions{
Project: project,
All: opts.All,
Services: services,
})

View File

@@ -43,7 +43,7 @@ func pullCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "pull [SERVICE...]",
Use: "pull [OPTIONS] [SERVICE...]",
Short: "Pull service images",
PreRunE: Adapt(func(ctx context.Context, args []string) error {
if opts.noParallel {
@@ -54,7 +54,7 @@ func pullCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPull(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information")

View File

@@ -29,6 +29,7 @@ type pushOptions struct {
composeOptions
Ignorefailures bool
Quiet bool
}
func pushCommand(p *projectOptions, backend api.Service) *cobra.Command {
@@ -36,14 +37,15 @@ func pushCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
pushCmd := &cobra.Command{
Use: "push [SERVICE...]",
Use: "push [OPTIONS] [SERVICE...]",
Short: "Push service images",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runPush(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures")
pushCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Push without printing progress information")
return pushCmd
}
@@ -56,5 +58,6 @@ func runPush(ctx context.Context, backend api.Service, opts pushOptions, service
return backend.Push(ctx, project, api.PushOptions{
IgnoreFailures: opts.Ignorefailures,
Quiet: opts.Quiet,
})
}

View File

@@ -35,7 +35,7 @@ func removeCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "rm [SERVICE...]",
Use: "rm [OPTIONS] [SERVICE...]",
Short: "Removes stopped service containers",
Long: `Removes stopped service containers
@@ -46,7 +46,7 @@ Any data which is not in a volume will be lost.`,
RunE: Adapt(func(ctx context.Context, args []string) error {
return runRemove(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
f := cmd.Flags()
f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal")
@@ -59,23 +59,25 @@ Any data which is not in a volume will be lost.`,
}
func runRemove(ctx context.Context, backend api.Service, opts removeOptions, services []string) error {
project, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
if opts.stop {
err := backend.Stop(ctx, project, api.StopOptions{
err := backend.Stop(ctx, name, api.StopOptions{
Services: services,
Project: project,
})
if err != nil {
return err
}
}
return backend.Remove(ctx, project, api.RemoveOptions{
return backend.Remove(ctx, name, api.RemoveOptions{
Services: services,
Force: opts.force,
Volumes: opts.volumes,
Project: project,
})
}

View File

@@ -35,12 +35,12 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
restartCmd := &cobra.Command{
Use: "restart [SERVICE...]",
Use: "restart [OPTIONS] [SERVICE...]",
Short: "Restart service containers",
RunE: Adapt(func(ctx context.Context, args []string) error {
return runRestart(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := restartCmd.Flags()
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
@@ -49,14 +49,15 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runRestart(ctx context.Context, backend api.Service, opts restartOptions, services []string) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
timeout := time.Duration(opts.timeout) * time.Second
return backend.Restart(ctx, projectName, api.RestartOptions{
return backend.Restart(ctx, name, api.RestartOptions{
Timeout: &timeout,
Services: services,
Project: project,
})
}

View File

@@ -114,7 +114,7 @@ func runCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *
},
}
cmd := &cobra.Command{
Use: "run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]",
Use: "run [OPTIONS] SERVICE [COMMAND] [ARGS...]",
Short: "Run a one-off command on a service.",
Args: cobra.MinimumNArgs(1),
PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
@@ -143,7 +143,7 @@ func runCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *
opts.ignoreOrphans = strings.ToLower(ignore) == "true"
return runRun(ctx, backend, project, opts)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
flags.BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID")
@@ -151,7 +151,7 @@ func runCommand(p *projectOptions, dockerCli command.Cli, backend api.Service) *
flags.StringArrayVarP(&opts.labels, "label", "l", []string{}, "Add or override a label")
flags.BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits")
flags.BoolVarP(&opts.noTty, "no-TTY", "T", !dockerCli.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).")
flags.StringVar(&opts.name, "name", "", " Assign a name to the container")
flags.StringVar(&opts.name, "name", "", "Assign a name to the container")
flags.StringVarP(&opts.user, "user", "u", "", "Run as specified username or uid")
flags.StringVarP(&opts.workdir, "workdir", "w", "", "Working directory inside the container")
flags.StringVar(&opts.entrypoint, "entrypoint", "", "Override the entrypoint of the image")

View File

@@ -37,18 +37,20 @@ func startCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runStart(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
return startCmd
}
func runStart(ctx context.Context, backend api.Service, opts startOptions, services []string) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
return backend.Start(ctx, projectName, api.StartOptions{
return backend.Start(ctx, name, api.StartOptions{
AttachTo: services,
Project: project,
Services: services,
})
}

View File

@@ -36,7 +36,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
projectOptions: p,
}
cmd := &cobra.Command{
Use: "stop [SERVICE...]",
Use: "stop [OPTIONS] [SERVICE...]",
Short: "Stop services",
PreRun: func(cmd *cobra.Command, args []string) {
opts.timeChanged = cmd.Flags().Changed("timeout")
@@ -44,7 +44,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runStop(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := cmd.Flags()
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
@@ -53,7 +53,7 @@ func stopCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
func runStop(ctx context.Context, backend api.Service, opts stopOptions, services []string) error {
projectName, err := opts.toProjectName()
project, name, err := opts.projectOrName()
if err != nil {
return err
}
@@ -63,8 +63,9 @@ func runStop(ctx context.Context, backend api.Service, opts stopOptions, service
timeoutValue := time.Duration(opts.timeout) * time.Second
timeout = &timeoutValue
}
return backend.Stop(ctx, projectName, api.StopOptions{
return backend.Stop(ctx, name, api.StopOptions{
Timeout: timeout,
Services: services,
Project: project,
})
}

View File

@@ -44,7 +44,7 @@ func topCommand(p *projectOptions, backend api.Service) *cobra.Command {
RunE: Adapt(func(ctx context.Context, args []string) error {
return runTop(ctx, backend, opts, args)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
return topCmd
}

35
cmd/compose/tracing.go Normal file
View File

@@ -0,0 +1,35 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compose
import (
"github.com/moby/buildkit/util/tracing/detect"
"go.opentelemetry.io/otel"
_ "github.com/moby/buildkit/util/tracing/detect/delegated" //nolint:blank-imports
_ "github.com/moby/buildkit/util/tracing/env" //nolint:blank-imports
)
func init() {
detect.ServiceName = "compose"
// do not log tracing errors to stdio
otel.SetErrorHandler(skipErrors{})
}
type skipErrors struct{}
func (skipErrors) Handle(err error) {}

View File

@@ -96,7 +96,7 @@ func upCommand(p *projectOptions, backend api.Service) *cobra.Command {
up := upOptions{}
create := createOptions{}
upCmd := &cobra.Command{
Use: "up [SERVICE...]",
Use: "up [OPTIONS] [SERVICE...]",
Short: "Create and start containers",
PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {
create.timeChanged = cmd.Flags().Changed("timeout")
@@ -109,7 +109,7 @@ func upCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
return runUp(ctx, backend, create, up, project, services)
}),
ValidArgsFunction: serviceCompletion(p),
ValidArgsFunction: completeServiceNames(p),
}
flags := upCmd.Flags()
flags.BoolVarP(&up.Detach, "detach", "d", false, "Detached mode: Run containers in the background")

View File

@@ -35,13 +35,18 @@ type versionOptions struct {
func versionCommand() *cobra.Command {
opts := versionOptions{}
cmd := &cobra.Command{
Use: "version",
Use: "version [OPTIONS]",
Short: "Show the Docker Compose version information",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
runVersion(opts)
return nil
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// overwrite parent PersistentPreRunE to avoid trying to load
// compose file on version command if COMPOSE_FILE is set
return nil
},
}
// define flags for backward compatibility with com.docker.cli
flags := cmd.Flags()

View File

@@ -89,7 +89,7 @@ func (l *logConsumer) Log(container, service, message string) {
}
p := l.getPresenter(container)
for _, line := range strings.Split(message, "\n") {
fmt.Fprintf(l.writer, "%s%s\n", p.prefix, line) //nolint:errcheck
fmt.Fprintf(l.writer, "%s%s\n", p.prefix, line)
}
}

View File

@@ -34,14 +34,13 @@ import (
func pluginMain() {
plugin.Run(func(dockerCli command.Cli) *cobra.Command {
lazyInit := api.NewServiceProxy()
cmd := commands.RootCommand(dockerCli, lazyInit)
serviceProxy := api.NewServiceProxy().WithService(compose.NewComposeService(dockerCli))
cmd := commands.RootCommand(dockerCli, serviceProxy)
originalPreRun := cmd.PersistentPreRunE
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if err := plugin.PersistentPreRunE(cmd, args); err != nil {
return err
}
lazyInit.WithService(compose.NewComposeService(dockerCli))
if originalPreRun != nil {
return originalPreRun(cmd, args)
}

132
docker-bake.hcl Normal file
View File

@@ -0,0 +1,132 @@
// Copyright 2022 Docker Compose CLI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
variable "GO_VERSION" {
default = "1.19.2"
}
variable "BUILD_TAGS" {
default = "e2e,kube"
}
variable "DOCS_FORMATS" {
default = "md,yaml"
}
# Defines the output folder
variable "DESTDIR" {
default = ""
}
function "bindir" {
params = [defaultdir]
result = DESTDIR != "" ? DESTDIR : "./bin/${defaultdir}"
}
target "_common" {
args = {
GO_VERSION = GO_VERSION
BUILD_TAGS = BUILD_TAGS
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
}
}
group "default" {
targets = ["binary"]
}
group "validate" {
targets = ["lint", "vendor-validate", "license-validate"]
}
target "lint" {
inherits = ["_common"]
target = "lint"
output = ["type=cacheonly"]
}
target "license-validate" {
target = "license-validate"
output = ["type=cacheonly"]
}
target "license-update" {
target = "license-update"
output = ["."]
}
target "vendor-validate" {
inherits = ["_common"]
target = "vendor-validate"
output = ["type=cacheonly"]
}
target "modules-validate" {
inherits = ["_common"]
target = "modules-validate"
output = ["type=cacheonly"]
}
target "vendor" {
inherits = ["_common"]
target = "vendor-update"
output = ["."]
}
target "test" {
inherits = ["_common"]
target = "test-coverage"
output = [bindir("coverage")]
}
target "binary" {
inherits = ["_common"]
target = "binary"
output = [bindir("build")]
platforms = ["local"]
}
target "binary-cross" {
inherits = ["binary"]
platforms = [
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm/v6",
"linux/arm/v7",
"linux/arm64",
"linux/ppc64le",
"linux/riscv64",
"linux/s390x",
"windows/amd64",
"windows/arm64"
]
}
target "release" {
inherits = ["binary-cross"]
target = "release"
output = [bindir("release")]
}
target "docs-validate" {
inherits = ["_common"]
target = "docs-validate"
output = ["type=cacheonly"]
}
target "docs-update" {
inherits = ["_common"]
target = "docs-update"
output = ["./docs"]
}

View File

@@ -1,57 +0,0 @@
# syntax=docker/dockerfile:1.3-labs
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
ARG GO_VERSION=1.18.4
ARG FORMATS=md,yaml
FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS docsgen
WORKDIR /src
RUN --mount=target=. \
--mount=target=/root/.cache,type=cache \
go build -o /out/docsgen ./docs/yaml/main/generate.go
FROM --platform=${BUILDPLATFORM} alpine AS gen
RUN apk add --no-cache rsync git
WORKDIR /src
COPY --from=docsgen /out/docsgen /usr/bin
ARG FORMATS
RUN --mount=target=/context \
--mount=target=.,type=tmpfs <<EOT
set -e
rsync -a /context/. .
docsgen --formats "$FORMATS" --source "docs/reference"
mkdir /out
cp -r docs/reference /out
EOT
FROM scratch AS update
COPY --from=gen /out /out
FROM gen AS validate
RUN --mount=target=/context \
--mount=target=.,type=tmpfs <<EOT
set -e
rsync -a /context/. .
git add -A
rm -rf docs/reference/*
cp -rf /out/* ./docs/
if [ -n "$(git status --porcelain -- docs/reference)" ]; then
echo >&2 'ERROR: Docs result differs. Please update with "make docs"'
git status --porcelain -- docs/reference
exit 1
fi
EOT

View File

@@ -10,7 +10,7 @@ Stop and remove containers, networks
| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. |
| `--rmi` | `string` | | Remove images used by services. "local" remove only images that don't have a custom tag ("local"\|"all") |
| `-t`, `--timeout` | `int` | `10` | Specify a shutdown timeout in seconds |
| `-v`, `--volumes` | | | Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. |
| `-v`, `--volumes` | | | Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. |
<!---MARKER_GEN_END-->

View File

@@ -7,6 +7,7 @@ Force stop service containers.
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `--remove-orphans` | | | Remove containers for services not defined in the Compose file. |
| `-s`, `--signal` | `string` | `SIGKILL` | SIGNAL to send to the container. |

View File

@@ -8,6 +8,7 @@ Push service images
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `--ignore-push-failures` | | | Push what it can and ignores images with push failures |
| `-q`, `--quiet` | | | Push without printing progress information |
<!---MARKER_GEN_END-->

View File

@@ -12,7 +12,7 @@ Run a one-off command on a service.
| `-e`, `--env` | `stringArray` | | Set environment variables |
| `-i`, `--interactive` | | | Keep STDIN open even if not attached. |
| `-l`, `--label` | `stringArray` | | Add or override a label |
| `--name` | `string` | | Assign a name to the container |
| `--name` | `string` | | Assign a name to the container |
| `-T`, `--no-TTY` | | | Disable pseudo-TTY allocation (default: auto-detected). |
| `--no-deps` | | | Don't start linked services. |
| `-p`, `--publish` | `stringArray` | | Publish a container's port(s) to the host. |

View File

@@ -10,7 +10,7 @@ long: |-
If you change a service's `Dockerfile` or the contents of its build directory,
run `docker compose build` to rebuild it.
usage: docker compose build [SERVICE...]
usage: docker compose build [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -7,7 +7,7 @@ long: |-
fully defined Compose model.
To allow smooth migration from docker-compose, this subcommand declares alias `docker compose config`
usage: docker compose convert SERVICES
usage: docker compose convert [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -1,7 +1,7 @@
command: docker compose create
short: Creates containers for a service.
long: Creates containers for a service.
usage: docker compose create [SERVICE...]
usage: docker compose create [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -14,7 +14,7 @@ long: |-
Anonymous volumes are not removed by default. However, as they dont have a stable name, they will not be automatically
mounted by a subsequent `up`. For data that needs to persist between updates, use explicit paths as bind mounts or
named volumes.
usage: docker compose down
usage: docker compose down [OPTIONS]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -20,7 +20,7 @@ long: |-
```
The events that can be received using this can be seen [here](/engine/reference/commandline/events/#object-types).
usage: docker compose events [options] [--] [SERVICE...]
usage: docker compose events [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -5,7 +5,7 @@ long: |-
With this subcommand you can run arbitrary commands in your services. Commands are by default allocating a TTY, so
you can use a command such as `docker compose exec web sh` to get an interactive prompt.
usage: docker compose exec [options] [-e KEY=VAL...] [--] SERVICE COMMAND [ARGS...]
usage: docker compose exec [OPTIONS] SERVICE COMMAND [ARGS...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -1,7 +1,7 @@
command: docker compose images
short: List images used by the created containers
long: List images used by the created containers
usage: docker compose images [SERVICE...]
usage: docker compose images [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -6,10 +6,20 @@ long: |-
```console
$ docker-compose kill -s SIGINT
```
usage: docker compose kill [options] [SERVICE...]
usage: docker compose kill [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:
- option: remove-orphans
value_type: bool
default_value: "false"
description: Remove containers for services not defined in the Compose file.
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: signal
shorthand: s
value_type: string

View File

@@ -1,7 +1,7 @@
command: docker compose logs
short: View output from containers
long: Displays log output from services.
usage: docker compose logs [SERVICE...]
usage: docker compose logs [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -1,7 +1,7 @@
command: docker compose ls
short: List running compose projects
long: List Compose projects running on platform.
usage: docker compose ls
usage: docker compose ls [OPTIONS]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -1,7 +1,7 @@
command: docker compose port
short: Print the public port for a port binding.
long: Prints the public port for a port binding.
usage: docker compose port [options] [--] SERVICE PRIVATE_PORT
usage: docker compose port [OPTIONS] SERVICE PRIVATE_PORT
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -10,7 +10,7 @@ long: |-
example-bar-1 "/docker-entrypoint.…" bar exited (0)
example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp
```
usage: docker compose ps [SERVICE...]
usage: docker compose ps [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -3,7 +3,7 @@ short: Pull service images
long: |-
Pulls an image associated with a service defined in a `compose.yaml` file, but does not start containers based on
those images.
usage: docker compose pull [SERVICE...]
usage: docker compose pull [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -19,7 +19,7 @@ long: |-
build: .
image: your-dockerid/yourimage ## goes to your repository on Docker Hub
```
usage: docker compose push [SERVICE...]
usage: docker compose push [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:
@@ -33,6 +33,17 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: quiet
shorthand: q
value_type: bool
default_value: "false"
description: Push without printing progress information
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
deprecated: false
experimental: false
experimentalcli: false

View File

@@ -11,7 +11,7 @@ long: |-
If you are looking to configure a service's restart policy, please refer to
[restart](https://github.com/compose-spec/compose-spec/blob/master/spec.md#restart)
or [restart_policy](https://github.com/compose-spec/compose-spec/blob/master/deploy.md#restart_policy).
usage: docker compose restart [SERVICE...]
usage: docker compose restart [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -16,7 +16,7 @@ long: |-
Are you sure? [yN] y
Removing djangoquickstart_web_run_1 ... done
```
usage: docker compose rm [SERVICE...]
usage: docker compose rm [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -54,7 +54,7 @@ long: |-
This runs a database upgrade script, and removes the container when finished running, even if a restart policy is
specified in the service configuration.
usage: docker compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]
usage: docker compose run [OPTIONS] SERVICE [COMMAND] [ARGS...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -2,7 +2,7 @@ command: docker compose stop
short: Stop services
long: |
Stops running containers without removing them. They can be started again with `docker compose start`.
usage: docker compose stop [SERVICE...]
usage: docker compose stop [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -17,7 +17,7 @@ long: |-
If the process encounters an error, the exit code for this command is `1`.
If the process is interrupted using `SIGINT` (ctrl + C) or `SIGTERM`, the containers are stopped, and the exit code is `0`.
usage: docker compose up [SERVICE...]
usage: docker compose up [OPTIONS] [SERVICE...]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -1,7 +1,7 @@
command: docker compose version
short: Show the Docker Compose version information
long: Show the Docker Compose version information
usage: docker compose version
usage: docker compose version [OPTIONS]
pname: docker compose
plink: docker_compose.yaml
options:

View File

@@ -0,0 +1,5 @@
Feature: Down
Scenario: No resources to remove
When I run "compose down"
Then the output contains "Warning: No resource found to remove for project "no_resources_to_remove""

View File

@@ -0,0 +1,15 @@
Feature: Simple service up
Background:
Given a compose file
"""
services:
simple:
image: alpine
command: top
"""
Scenario: compose up
When I run "compose up -d"
Then the output contains "simple-1 Started"
And service "simple" is "running"

View File

@@ -0,0 +1,21 @@
Feature: Start
Background:
Given a compose file
"""
services:
simple:
image: alpine
command: top
another:
image: alpine
command: top
"""
Scenario: Start single service
When I run "compose create"
Then the output contains "simple-1 Created"
And the output contains "another-1 Created"
Then I run "compose start another"
And service "another" is "running"
And service "simple" is "created"

View File

@@ -0,0 +1,30 @@
Feature: Stop
Background:
Given a compose file
"""
services:
should_fail:
image: alpine
command: ls /does_not_exist
sleep: # will be killed
image: alpine
command: ping localhost
"""
Scenario: Cascade stop
When I run "compose up --abort-on-container-exit"
Then the output contains "should_fail-1 exited with code 1"
And the output contains "Aborting on container exit..."
And the exit code is 1
Scenario: Exit code from
When I run "compose up --exit-code-from sleep"
Then the output contains "should_fail-1 exited with code 1"
And the output contains "Aborting on container exit..."
And the exit code is 137
Scenario: Exit code from unknown service
When I run "compose up --exit-code-from unknown"
Then the output contains "no such service: unknown"
And the exit code is 1

129
e2e/cucumber_test.go Normal file
View File

@@ -0,0 +1,129 @@
/*
Copyright 2022 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cucumber
import (
"context"
"fmt"
"os"
"regexp"
"strings"
"testing"
"github.com/cucumber/godog"
"github.com/cucumber/godog/colors"
"github.com/docker/compose/v2/pkg/e2e"
"gotest.tools/v3/icmd"
)
func TestCucumber(t *testing.T) {
testingOptions := godog.Options{
TestingT: t,
Paths: []string{"./cucumber-features"},
Output: colors.Colored(os.Stdout),
Format: "pretty",
}
status := godog.TestSuite{
Name: "godogs",
Options: &testingOptions,
ScenarioInitializer: setup,
}.Run()
if status == 2 {
t.SkipNow()
}
if status != 0 {
t.Fatalf("zero status code expected, %d received", status)
}
}
func setup(s *godog.ScenarioContext) {
t := s.TestingT()
cli := e2e.NewCLI(t, e2e.WithEnv(
fmt.Sprintf("COMPOSE_PROJECT_NAME=%s", strings.Split(t.Name(), "/")[1]),
))
th := testHelper{
T: t,
CLI: cli,
}
s.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
return ctx, nil
})
s.After(func(ctx context.Context, sc *godog.Scenario, err error) (context.Context, error) {
cli.RunDockerComposeCmd(t, "down", "--remove-orphans", "-v", "-t", "0")
return ctx, nil
})
s.Step(`^a compose file$`, th.setComposeFile)
s.Step(`^I run "compose (.*)"$`, th.runComposeCommand)
s.Step(`service "(.*)" is "(.*)"$`, th.serviceIsStatus)
s.Step(`output contains "(.*)"$`, th.outputContains)
s.Step(`exit code is (\d+)$`, th.exitCodeIs)
}
type testHelper struct {
T *testing.T
ComposeFile string
CommandOutput string
CommandExitCode int
CLI *e2e.CLI
}
func (th *testHelper) serviceIsStatus(service, status string) error {
res := th.CLI.RunDockerComposeCmd(th.T, "ps", "-a")
statusRegex := fmt.Sprintf("%s\\s+%s", service, status)
r, _ := regexp.Compile(statusRegex)
if !r.MatchString(res.Combined()) {
return fmt.Errorf("Missing/incorrect ps output:\n%s", res.Combined())
}
return nil
}
func (th *testHelper) outputContains(substring string) error {
if !strings.Contains(th.CommandOutput, substring) {
return fmt.Errorf("Missing output substring: %s\noutput: %s", substring, th.CommandOutput)
}
return nil
}
func (th *testHelper) exitCodeIs(exitCode int) error {
if exitCode != th.CommandExitCode {
return fmt.Errorf("Wrong exit code: %d expected: %d", th.CommandExitCode, exitCode)
}
return nil
}
func (th *testHelper) runComposeCommand(command string) error {
commandArgs := []string{"-f", "-"}
commandArgs = append(commandArgs, strings.Split(command, " ")...)
cmd := th.CLI.NewDockerComposeCmd(th.T, commandArgs...)
cmd.Stdin = strings.NewReader(th.ComposeFile)
res := icmd.RunCmd(cmd)
th.CommandOutput = res.Combined()
th.CommandExitCode = res.ExitCode
return nil
}
func (th *testHelper) setComposeFile(composeString string) error {
th.ComposeFile = composeString
return nil
}

171
e2e/go.mod Normal file
View File

@@ -0,0 +1,171 @@
module github.com/docker/compose/v2/e2e
go 1.19
replace github.com/docker/compose/v2 => ../
replace github.com/cucumber/godog => github.com/laurazard/godog v0.0.0-20220922095256-4c4b17abdae7
require (
github.com/cucumber/godog v0.12.5
github.com/docker/compose/v2 v2.11.1
gotest.tools/v3 v3.4.0
)
require (
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cnabio/cnab-go v0.23.4 // indirect
github.com/cnabio/cnab-to-oci v0.3.7 // indirect
github.com/compose-spec/compose-go v1.6.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/containerd/containerd v1.6.8 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/containerd/ttrpc v1.1.0 // indirect
github.com/containerd/typeurl v1.0.2 // indirect
github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect
github.com/cucumber/messages-go/v16 v16.0.1 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/distribution/v3 v3.0.0-20220907155224-78b9c98c5c31 // indirect
github.com/docker/buildx v0.9.1 // indirect
github.com/docker/cli v20.10.19+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.19+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gofrs/flock v0.8.0 // indirect
github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-memdb v1.3.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/buildkit v0.10.4 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/symlink v0.2.0 // indirect
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1 // indirect
github.com/opencontainers/runc v1.1.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
github.com/qri-io/jsonschema v0.2.2-0.20210831022256-780655b2ba0e // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/cobra v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.0 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect
github.com/weppos/publicsuffix-go v0.20.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 // indirect
go.opentelemetry.io/otel v1.11.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 // indirect
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
go.opentelemetry.io/otel/metric v0.27.0 // indirect
go.opentelemetry.io/otel/sdk v1.4.1 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.24.1 // indirect
k8s.io/apimachinery v0.24.1 // indirect
k8s.io/client-go v0.24.1 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
replace (
github.com/docker/cli => github.com/docker/cli v20.10.3-0.20221013132413-1d6c6e2367e2+incompatible // 22.06 master branch
github.com/docker/docker => github.com/docker/docker v20.10.3-0.20221021173910-5aac513617f0+incompatible // 22.06 branch
github.com/moby/buildkit => github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a // same as buildx
github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.2 // Can be removed on next bump of containerd to > 1.6.4
// For k8s dependencies, we use a replace directive, to prevent them being
// upgraded to the version specified in containerd, which is not relevant to the
// version needed.
// See https://github.com/docker/buildx/pull/948 for details.
// https://github.com/docker/buildx/blob/v0.8.1/go.mod#L62-L64
k8s.io/api => k8s.io/api v0.22.4
k8s.io/apimachinery => k8s.io/apimachinery v0.22.4
k8s.io/client-go => k8s.io/client-go v0.22.4
)

1041
e2e/go.sum Normal file

File diff suppressed because it is too large Load Diff

88
go.mod
View File

@@ -1,41 +1,41 @@
module github.com/docker/compose/v2
go 1.18
go 1.19
require (
github.com/AlecAivazis/survey/v2 v2.3.5
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/buger/goterm v1.0.4
github.com/cnabio/cnab-to-oci v0.3.5
github.com/compose-spec/compose-go v1.3.0
github.com/cnabio/cnab-to-oci v0.3.7
github.com/compose-spec/compose-go v1.6.0
github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.6.6
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb
github.com/docker/buildx v0.8.2 // when updating, also update the replace rules accordingly
github.com/docker/cli v20.10.17+incompatible
github.com/containerd/containerd v1.6.8
github.com/distribution/distribution/v3 v3.0.0-20220907155224-78b9c98c5c31
github.com/docker/buildx v0.9.1 // when updating, also update the replace rules accordingly
github.com/docker/cli v20.10.19+incompatible // v22.06.x - see "replace" for the actual version
github.com/docker/cli-docs-tool v0.5.0
github.com/docker/docker v20.10.17+incompatible
github.com/docker/docker v20.10.19+incompatible // v22.06.x - see "replace" for the actual version
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.4.0
github.com/docker/go-units v0.5.0
github.com/golang/mock v1.6.0
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.6.0
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-isatty v0.0.16
github.com/mattn/go-shellwords v1.0.12
github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/moby/buildkit v0.10.4 // see "replace" for the actual version
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae
github.com/morikuni/aec v1.0.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1
github.com/pkg/errors v0.9.1
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.5.0
github.com/spf13/cobra v1.6.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
github.com/theupdateframework/notary v0.7.0
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
gotest.tools/v3 v3.3.0
gotest.tools/v3 v3.4.0
)
require (
@@ -45,7 +45,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cnabio/cnab-go v0.23.4 // indirect
github.com/containerd/continuity v0.2.2 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/containerd/ttrpc v1.1.0 // indirect
github.com/containerd/typeurl v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -55,13 +55,13 @@ require (
github.com/docker/go-metrics v0.0.1 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gofrs/flock v0.8.0 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/mux v1.8.0 // indirect
@@ -69,30 +69,30 @@ require (
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/sys/signal v0.6.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/symlink v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/opencontainers/runc v1.1.2 // indirect
github.com/opencontainers/runc v1.1.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
github.com/qri-io/jsonschema v0.2.2-0.20210831022256-780655b2ba0e // indirect
github.com/tonistiigi/fsutil v0.0.0-20220315205639-9ed612626da3 // indirect
github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20210615222946-8066bb97264f // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -101,29 +101,28 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 // indirect
go.opentelemetry.io/otel v1.4.1 // indirect
go.opentelemetry.io/otel v1.11.1
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
go.opentelemetry.io/otel/metric v0.27.0 // indirect
go.opentelemetry.io/otel/sdk v1.4.1 // indirect
go.opentelemetry.io/otel/trace v1.4.1 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.24.1 // indirect; see replace for the actual version used
k8s.io/client-go v0.24.1 // indirect; see replace for the actual version used
k8s.io/client-go v0.24.1 // see replace for the actual version used
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
@@ -131,14 +130,27 @@ require (
)
require (
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
github.com/zmap/zcrypto v0.0.0-20220605182715-4dfcec6e9a8c // indirect
github.com/zmap/zlint v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 // indirect
k8s.io/api v0.24.1 // indirect
)
replace (
github.com/docker/cli => github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible
github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220309172631-83b51522df43+incompatible
github.com/docker/cli => github.com/docker/cli v20.10.3-0.20221013132413-1d6c6e2367e2+incompatible // 22.06 master branch
github.com/docker/docker => github.com/docker/docker v20.10.3-0.20221021173910-5aac513617f0+incompatible // 22.06 branch
github.com/moby/buildkit => github.com/moby/buildkit v0.10.1-0.20220816171719-55ba9d14360a // same as buildx
github.com/opencontainers/runc => github.com/opencontainers/runc v1.1.2 // Can be removed on next bump of containerd to > 1.6.4

1388
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ import (
type Service interface {
// Build executes the equivalent to a `compose build`
Build(ctx context.Context, project *types.Project, options BuildOptions) error
// Push executes the equivalent ot a `compose push`
// Push executes the equivalent to a `compose push`
Push(ctx context.Context, project *types.Project, options PushOptions) error
// Pull executes the equivalent of a `compose pull`
Pull(ctx context.Context, project *types.Project, options PullOptions) error
@@ -117,7 +117,7 @@ type CreateOptions struct {
// StartOptions group options of the Start API
type StartOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran `start` just with project name
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
// Attach to container and forward logs if not nil
Attach LogConsumer
@@ -129,10 +129,14 @@ type StartOptions struct {
ExitCodeFrom string
// Wait won't return until containers reached the running|healthy state
Wait bool
// Services passed in the command line to be started
Services []string
}
// RestartOptions group options of the Restart API
type RestartOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
// Timeout override container restart timeout
Timeout *time.Duration
// Services passed in the command line to be restarted
@@ -141,6 +145,8 @@ type RestartOptions struct {
// StopOptions group options of the Stop API
type StopOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
// Timeout override container stop timeout
Timeout *time.Duration
// Services passed in the command line to be stopped
@@ -177,6 +183,7 @@ type ConvertOptions struct {
// PushOptions group options of the Push API
type PushOptions struct {
Quiet bool
IgnoreFailures bool
}
@@ -193,6 +200,10 @@ type ImagesOptions struct {
// KillOptions group options of the Kill API
type KillOptions struct {
// RemoveOrphans will cleanup containers that are not declared on the compose model but own the same labels
RemoveOrphans bool
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
// Services passed in the command line to be killed
Services []string
// Signal to send to containers
@@ -201,6 +212,8 @@ type KillOptions struct {
// RemoveOptions group options of the Remove API
type RemoveOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
// DryRun just list removable resources
DryRun bool
// Volumes remove anonymous volumes
@@ -213,6 +226,8 @@ type RemoveOptions struct {
// RunOptions group options of the Run API
type RunOptions struct {
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
Name string
Service string
Command []string
@@ -272,6 +287,7 @@ type ListOptions struct {
// PsOptions group options of the Ps API
type PsOptions struct {
Project *types.Project
All bool
Services []string
}
@@ -365,6 +381,7 @@ type ServiceStatus struct {
// LogOptions defines optional parameters for the `Log` API
type LogOptions struct {
Project *types.Project
Services []string
Tail string
Since string
@@ -377,6 +394,8 @@ type LogOptions struct {
type PauseOptions struct {
// Services passed in the command line to be started
Services []string
// Project is the compose project used to define this app. Might be nil if user ran command just with project name
Project *types.Project
}
const (
@@ -414,7 +433,7 @@ type Stack struct {
// LogConsumer is a callback to process log messages from services
type LogConsumer interface {
Log(service, container, message string)
Log(containerName, service, message string)
Status(container, msg string)
Register(container string)
}
@@ -424,7 +443,11 @@ type ContainerEventListener func(event ContainerEvent)
// ContainerEvent notify an event has been collected on source container implementing Service
type ContainerEvent struct {
Type int
Type int
// Container is the name of the container _without the project prefix_.
//
// This is only suitable for display purposes within Compose, as it's
// not guaranteed to be unique across services.
Container string
Service string
Line string

View File

@@ -51,8 +51,10 @@ const (
ImageDigestLabel = "com.docker.compose.image"
// DependenciesLabel stores service dependencies
DependenciesLabel = "com.docker.compose.depends_on"
// VersionLabel stores the compose tool version used to run application
// VersionLabel stores the compose tool version used to build/run application
VersionLabel = "com.docker.compose.version"
// ImageBuilderLabel stores the builder (classic or BuildKit) used to produce the image.
ImageBuilderLabel = "com.docker.compose.image.builder"
)
// ComposeVersion is the compose tool version as declared by label VersionLabel

View File

@@ -22,6 +22,8 @@ import (
"github.com/compose-spec/compose-go/types"
)
var _ Service = &ServiceProxy{}
// ServiceProxy implements Service by delegating to implementation functions. This allows lazy init and per-method overrides
type ServiceProxy struct {
BuildFn func(ctx context.Context, project *types.Project, options BuildOptions) error
@@ -59,8 +61,6 @@ func NewServiceProxy() *ServiceProxy {
// Interceptor allow to customize the compose types.Project before the actual Service method is executed
type Interceptor func(ctx context.Context, project *types.Project)
var _ Service = &ServiceProxy{}
// WithService configure proxy to use specified Service as delegate
func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
s.BuildFn = service.Build

View File

@@ -27,7 +27,7 @@ import (
_ "github.com/docker/buildx/driver/docker" // required to get default driver registered
"github.com/docker/buildx/util/buildflags"
xprogress "github.com/docker/buildx/util/progress"
"github.com/docker/docker/pkg/urlutil"
"github.com/docker/docker/builder/remotecontext/urlutil"
bclient "github.com/moby/buildkit/client"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth/authprovider"
@@ -50,10 +50,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
opts := map[string]build.Options{}
var imagesToBuild []string
args := flatten(options.Args.Resolve(func(s string) (string, bool) {
s, ok := project.Environment[s]
return s, ok
}))
args := flatten(options.Args.Resolve(envResolver(project.Environment)))
services, err := project.GetServices(options.Services...)
if err != nil {
@@ -84,6 +81,18 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
Attrs: map[string]string{"ref": image},
})
}
buildOptions.Exports = []bclient.ExportEntry{{
Type: "docker",
Attrs: map[string]string{
"load": "true",
},
}}
if len(buildOptions.Platforms) > 1 {
buildOptions.Exports = []bclient.ExportEntry{{
Type: "image",
Attrs: map[string]string{},
}}
}
opts[imageName] = buildOptions
}
@@ -141,7 +150,7 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types.
if project.Services[i].Labels == nil {
project.Services[i].Labels = types.Labels{}
}
project.Services[i].CustomLabels[api.ImageDigestLabel] = digest
project.Services[i].CustomLabels.Add(api.ImageDigestLabel, digest)
}
}
return nil
@@ -164,6 +173,15 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
if err != nil {
return nil, err
}
opt.Exports = []bclient.ExportEntry{{
Type: "docker",
Attrs: map[string]string{
"load": "true",
},
}}
if opt.Platforms, err = useDockerDefaultOrServicePlatform(project, service, true); err != nil {
opt.Platforms = []specs.Platform{}
}
opts[imageName] = opt
continue
}
@@ -207,32 +225,18 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
if buildkitEnabled, err := s.dockerCli.BuildKitEnabled(); err != nil || !buildkitEnabled {
return s.doBuildClassic(ctx, project, opts)
}
return s.doBuildBuildkit(ctx, project, opts, mode)
return s.doBuildBuildkit(ctx, opts, mode)
}
func (s *composeService) toBuildOptions(project *types.Project, service types.ServiceConfig, imageTag string, sshKeys []types.SSHKey) (build.Options, error) {
var tags []string
tags = append(tags, imageTag)
buildArgs := flatten(service.Build.Args.Resolve(func(s string) (string, bool) {
s, ok := project.Environment[s]
return s, ok
}))
buildArgs := flatten(service.Build.Args.Resolve(envResolver(project.Environment)))
var plats []specs.Platform
if platform, ok := project.Environment["DOCKER_DEFAULT_PLATFORM"]; ok {
p, err := platforms.Parse(platform)
if err != nil {
return build.Options{}, err
}
plats = append(plats, p)
}
if service.Platform != "" {
p, err := platforms.Parse(service.Platform)
if err != nil {
return build.Options{}, err
}
plats = append(plats, p)
plats, err := addPlatforms(project, service)
if err != nil {
return build.Options{}, err
}
cacheFrom, err := buildflags.ParseCacheEntry(service.Build.CacheFrom)
@@ -245,7 +249,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
}
sessionConfig := []session.Attachable{
authprovider.NewDockerAuthProvider(s.stderr()),
authprovider.NewDockerAuthProvider(s.configFile()),
}
if len(sshKeys) > 0 || len(service.Build.SSH) > 0 {
sshAgentProvider, err := sshAgentProvider(append(service.Build.SSH, sshKeys...))
@@ -267,6 +271,8 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
tags = append(tags, service.Build.Tags...)
}
imageLabels := getImageBuildLabels(project, service)
return build.Options{
Inputs: build.Inputs{
ContextPath: service.Build.Context,
@@ -281,7 +287,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
Target: service.Build.Target,
Exports: []bclient.ExportEntry{{Type: "image", Attrs: map[string]string{}}},
Platforms: plats,
Labels: service.Build.Labels,
Labels: imageLabels,
NetworkMode: service.Build.Network,
ExtraHosts: service.Build.ExtraHosts.AsList(),
Session: sessionConfig,
@@ -331,7 +337,6 @@ func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) {
}
func addSecretsConfig(project *types.Project, service types.ServiceConfig) (session.Attachable, error) {
var sources []secretsprovider.Source
for _, secret := range service.Build.Secrets {
config := project.Secrets[secret.Source]
@@ -356,3 +361,70 @@ func addSecretsConfig(project *types.Project, service types.ServiceConfig) (sess
}
return secretsprovider.NewSecretProvider(store), nil
}
func addPlatforms(project *types.Project, service types.ServiceConfig) ([]specs.Platform, error) {
plats, err := useDockerDefaultOrServicePlatform(project, service, false)
if err != nil {
return nil, err
}
for _, buildPlatform := range service.Build.Platforms {
p, err := platforms.Parse(buildPlatform)
if err != nil {
return nil, err
}
if !utils.Contains(plats, p) {
plats = append(plats, p)
}
}
return plats, nil
}
func getImageBuildLabels(project *types.Project, service types.ServiceConfig) types.Labels {
ret := make(types.Labels)
if service.Build != nil {
for k, v := range service.Build.Labels {
ret.Add(k, v)
}
}
ret.Add(api.VersionLabel, api.ComposeVersion)
ret.Add(api.ProjectLabel, project.Name)
ret.Add(api.ServiceLabel, service.Name)
return ret
}
func useDockerDefaultPlatform(project *types.Project, platformList types.StringList) ([]specs.Platform, error) {
var plats []specs.Platform
if platform, ok := project.Environment["DOCKER_DEFAULT_PLATFORM"]; ok {
if len(platformList) > 0 && !utils.StringContains(platformList, platform) {
return nil, fmt.Errorf("the DOCKER_DEFAULT_PLATFORM %q value should be part of the service.build.platforms: %q", platform, platformList)
}
p, err := platforms.Parse(platform)
if err != nil {
return nil, err
}
plats = append(plats, p)
}
return plats, nil
}
func useDockerDefaultOrServicePlatform(project *types.Project, service types.ServiceConfig, useOnePlatform bool) ([]specs.Platform, error) {
plats, err := useDockerDefaultPlatform(project, service.Build.Platforms)
if (len(plats) > 0 && useOnePlatform) || err != nil {
return plats, err
}
if service.Platform != "" && !utils.StringContains(service.Build.Platforms, service.Platform) {
if len(service.Build.Platforms) > 0 {
return nil, fmt.Errorf("service.platform %q should be part of the service.build.platforms: %q", service.Platform, service.Build.Platforms)
}
// User defined a service platform and no build platforms, so we should keep the one define on the service level
p, err := platforms.Parse(service.Platform)
if !utils.Contains(plats, p) {
plats = append(plats, p)
}
return plats, err
}
return plats, nil
}

View File

@@ -18,27 +18,36 @@ package compose
import (
"context"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
ctxkube "github.com/docker/buildx/driver/kubernetes/context"
"github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/context/docker"
ctxstore "github.com/docker/cli/cli/context/store"
dockerclient "github.com/docker/docker/client"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"k8s.io/client-go/tools/clientcmd"
"github.com/compose-spec/compose-go/types"
"github.com/docker/buildx/build"
"github.com/docker/buildx/driver"
_ "github.com/docker/buildx/driver/docker" //nolint:blank-imports
_ "github.com/docker/buildx/driver/docker-container" //nolint:blank-imports
_ "github.com/docker/buildx/driver/kubernetes" //nolint:blank-imports
xprogress "github.com/docker/buildx/util/progress"
)
func (s *composeService) doBuildBuildkit(ctx context.Context, project *types.Project, opts map[string]build.Options, mode string) (map[string]string, error) {
const drivername = "default"
d, err := driver.GetDriver(ctx, drivername, nil, s.apiClient(), s.configFile(), nil, nil, nil, nil, nil, project.WorkingDir)
func (s *composeService) doBuildBuildkit(ctx context.Context, opts map[string]build.Options, mode string) (map[string]string, error) {
dis, err := s.getDrivers(ctx)
if err != nil {
return nil, err
}
driverInfo := []build.DriverInfo{
{
Name: drivername,
Driver: d,
},
}
// Progress needs its own context that lives longer than the
// build one otherwise it won't read all the messages from
@@ -47,8 +56,7 @@ func (s *composeService) doBuildBuildkit(ctx context.Context, project *types.Pro
defer cancel()
w := xprogress.NewPrinter(progressCtx, s.stdout(), os.Stdout, mode)
// We rely on buildx "docker" builder integrated in docker engine, so don't need a DockerAPI here
response, err := build.Build(ctx, driverInfo, opts, nil, filepath.Dir(s.configFile().Filename), w)
response, err := build.Build(ctx, dis, opts, &internalAPI{dockerCli: s.dockerCli}, filepath.Dir(s.configFile().Filename), w)
errW := w.Wait()
if err == nil {
err = errW
@@ -71,3 +79,187 @@ func (s *composeService) doBuildBuildkit(ctx context.Context, project *types.Pro
return imagesBuilt, err
}
func (s *composeService) getDrivers(ctx context.Context) ([]build.DriverInfo, error) { //nolint:gocyclo
txn, release, err := storeutil.GetStore(s.dockerCli)
if err != nil {
return nil, err
}
defer release()
ng, err := storeutil.GetCurrentInstance(txn, s.dockerCli)
if err != nil {
return nil, err
}
dis := make([]build.DriverInfo, len(ng.Nodes))
var f driver.Factory
if ng.Driver != "" {
factories := driver.GetFactories(true)
for _, fac := range factories {
if fac.Name() == ng.Driver {
f = fac
continue
}
}
if f == nil {
if f, err = driver.GetFactory(ng.Driver, true); f == nil || err != nil {
return nil, fmt.Errorf("failed to find buildx driver %q, error: %w", ng.Driver, err)
}
}
} else {
ep := ng.Nodes[0].Endpoint
dockerapi, err := clientForEndpoint(s.dockerCli, ep)
if err != nil {
return nil, err
}
f, err = driver.GetDefaultFactory(ctx, ep, dockerapi, false)
if err != nil {
return nil, err
}
ng.Driver = f.Name()
}
imageopt, err := storeutil.GetImageConfig(s.dockerCli, ng)
if err != nil {
return nil, err
}
eg, _ := errgroup.WithContext(ctx)
for i, n := range ng.Nodes {
func(i int, n store.Node) {
eg.Go(func() error {
di := build.DriverInfo{
Name: n.Name,
Platform: n.Platforms,
ProxyConfig: storeutil.GetProxyConfig(s.dockerCli),
}
defer func() {
dis[i] = di
}()
dockerapi, err := clientForEndpoint(s.dockerCli, n.Endpoint)
if err != nil {
di.Err = err
return nil
}
// TODO: replace the following line with dockerclient.WithAPIVersionNegotiation option in clientForEndpoint
dockerapi.NegotiateAPIVersion(ctx)
contextStore := s.dockerCli.ContextStore()
var kcc driver.KubeClientConfig
kcc, err = configFromContext(n.Endpoint, contextStore)
if err != nil {
// err is returned if n.Endpoint is non-context name like "unix:///var/run/docker.sock".
// try again with name="default".
// FIXME: n should retain real context name.
kcc, err = configFromContext("default", contextStore)
if err != nil {
logrus.Error(err)
}
}
tryToUseKubeConfigInCluster := false
if kcc == nil {
tryToUseKubeConfigInCluster = true
} else {
if _, err := kcc.ClientConfig(); err != nil {
tryToUseKubeConfigInCluster = true
}
}
if tryToUseKubeConfigInCluster {
kccInCluster := driver.KubeClientConfigInCluster{}
if _, err := kccInCluster.ClientConfig(); err == nil {
logrus.Debug("using kube config in cluster")
kcc = kccInCluster
}
}
d, err := driver.GetDriver(ctx, "buildx_buildkit_"+n.Name, f, n.Endpoint, dockerapi, imageopt.Auth, kcc, n.Flags, n.Files, n.DriverOpts, n.Platforms, "")
if err != nil {
di.Err = err
return nil
}
di.Driver = d
di.ImageOpt = imageopt
return nil
})
}(i, n)
}
if err := eg.Wait(); err != nil {
return nil, err
}
return dis, nil
}
func clientForEndpoint(dockerCli command.Cli, name string) (dockerclient.APIClient, error) {
list, err := dockerCli.ContextStore().List()
if err != nil {
return nil, err
}
for _, l := range list {
if l.Name != name {
continue
}
dep, ok := l.Endpoints["docker"]
if !ok {
return nil, fmt.Errorf("context %q does not have a Docker endpoint", name)
}
epm, ok := dep.(docker.EndpointMeta)
if !ok {
return nil, fmt.Errorf("endpoint %q is not of type EndpointMeta, %T", dep, dep)
}
ep, err := docker.WithTLSData(dockerCli.ContextStore(), name, epm)
if err != nil {
return nil, err
}
clientOpts, err := ep.ClientOpts()
if err != nil {
return nil, err
}
return dockerclient.NewClientWithOpts(clientOpts...)
}
ep := docker.Endpoint{
EndpointMeta: docker.EndpointMeta{
Host: name,
},
}
clientOpts, err := ep.ClientOpts()
if err != nil {
return nil, err
}
return dockerclient.NewClientWithOpts(clientOpts...)
}
func configFromContext(endpointName string, s ctxstore.Reader) (clientcmd.ClientConfig, error) {
if strings.HasPrefix(endpointName, "kubernetes://") {
u, _ := url.Parse(endpointName)
if kubeconfig := u.Query().Get("kubeconfig"); kubeconfig != "" {
_ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, kubeconfig)
}
rules := clientcmd.NewDefaultClientConfigLoadingRules()
apiConfig, err := rules.Load()
if err != nil {
return nil, err
}
return clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{}), nil
}
return ctxkube.ConfigFromContext(endpointName, s)
}
type internalAPI struct {
dockerCli command.Cli
}
func (a *internalAPI) DockerAPI(name string) (dockerclient.APIClient, error) {
if name == "" {
name = a.dockerCli.CurrentContext()
}
return clientForEndpoint(a.dockerCli, name)
}

View File

@@ -29,17 +29,18 @@ import (
"github.com/compose-spec/compose-go/types"
buildx "github.com/docker/buildx/build"
"github.com/docker/cli/cli/command/image/build"
"github.com/docker/compose/v2/pkg/api"
dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/builder/remotecontext/urlutil"
"github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/urlutil"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/docker/compose/v2/pkg/api"
)
func (s *composeService) doBuildClassic(ctx context.Context, project *types.Project, opts map[string]buildx.Options) (map[string]string, error) {
@@ -65,7 +66,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
return nameDigests, errs
}
//nolint: gocyclo
//nolint:gocyclo
func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options buildx.Options) (string, error) {
var (
buildCtx io.ReadCloser
@@ -88,6 +89,15 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options
}
}
if len(options.Platforms) > 1 {
return "", errors.Errorf("this builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use multi-arch builder")
}
if options.Labels == nil {
options.Labels = make(map[string]string)
}
options.Labels[api.ImageBuilderLabel] = "classic"
switch {
case isLocalDir(specifiedContext):
contextDir, relDockerfile, err = build.GetContextFromLocalDir(specifiedContext, dockerfileName)

View File

@@ -17,23 +17,24 @@
package compose
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"strings"
"gopkg.in/yaml.v2"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/streams"
"github.com/docker/compose/v2/pkg/api"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/sanathkr/go-yaml"
"github.com/docker/compose/v2/pkg/api"
)
// NewComposeService create a local implementation of the compose.Service API
@@ -94,28 +95,14 @@ func getContainerNameWithoutProject(c moby.Container) string {
func (s *composeService) Convert(ctx context.Context, project *types.Project, options api.ConvertOptions) ([]byte, error) {
switch options.Format {
case "json":
marshal, err := json.MarshalIndent(project, "", " ")
if err != nil {
return nil, err
}
return escapeDollarSign(marshal), nil
return json.MarshalIndent(project, "", " ")
case "yaml":
marshal, err := yaml.Marshal(project)
if err != nil {
return nil, err
}
return escapeDollarSign(marshal), nil
return yaml.Marshal(project)
default:
return nil, fmt.Errorf("unsupported format %q", options)
}
}
func escapeDollarSign(marshal []byte) []byte {
dollar := []byte{'$'}
escDollar := []byte{'$', '$'}
return bytes.ReplaceAll(marshal, dollar, escDollar)
}
// projectFromName builds a types.Project based on actual resources with compose labels set
func (s *composeService) projectFromName(containers Containers, projectName string, services ...string) (*types.Project, error) {
project := &types.Project{
@@ -172,26 +159,6 @@ SERVICES:
return project, nil
}
// actualState list resources labelled by projectName to rebuild compose project model
func (s *composeService) actualState(ctx context.Context, projectName string, services []string) (Containers, *types.Project, error) {
var containers Containers
// don't filter containers by options.Services so projectFromName can rebuild project with all existing resources
containers, err := s.getContainers(ctx, projectName, oneOffInclude, true)
if err != nil {
return nil, nil, err
}
project, err := s.projectFromName(containers, projectName, services...)
if err != nil && !api.IsNotFoundError(err) {
return nil, nil, err
}
if len(services) > 0 {
containers = containers.filter(isService(services...))
}
return containers, project, nil
}
func (s *composeService) actualVolumes(ctx context.Context, projectName string) (types.Volumes, error) {
volumes, err := s.apiClient().VolumeList(ctx, filters.NewArgs(projectFilter(projectName)))
if err != nil {

View File

@@ -30,13 +30,13 @@ const (
// ContainerRunning running status
ContainerRunning = "running"
// ContainerRemoving removing status
ContainerRemoving = "removing" //nolint
ContainerRemoving = "removing"
// ContainerPaused paused status
ContainerPaused = "paused" //nolint
ContainerPaused = "paused"
// ContainerExited exited status
ContainerExited = "exited" //nolint
ContainerExited = "exited"
// ContainerDead dead status
ContainerDead = "dead" //nolint
ContainerDead = "dead"
)
var _ io.ReadCloser = ContainerStdout{}

View File

@@ -27,6 +27,7 @@ import (
"github.com/compose-spec/compose-go/types"
"github.com/containerd/containerd/platforms"
moby "github.com/docker/docker/api/types"
containerType "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
specs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -180,7 +181,10 @@ func (c *convergence) ensureService(ctx context.Context, project *types.Project,
// Scale Down
container := container
eg.Go(func() error {
err := c.service.apiClient().ContainerStop(ctx, container.ID, timeout)
timeoutInSecond := utils.DurationSecondToInt(timeout)
err := c.service.apiClient().ContainerStop(ctx, container.ID, containerType.StopOptions{
Timeout: timeoutInSecond,
})
if err != nil {
return err
}
@@ -352,6 +356,12 @@ func shouldWaitForDependency(serviceName string, dependencyConfig types.ServiceD
return false, nil
}
if service, err := project.GetService(serviceName); err != nil {
for _, ds := range project.DisabledServices {
if ds.Name == serviceName {
// don't wait for disabled service (--no-deps)
return false, nil
}
}
return false, err
} else if service.Scale == 0 {
// don't wait for the dependency which configured to have 0 containers running
@@ -406,7 +416,8 @@ func (s *composeService) recreateContainer(ctx context.Context, project *types.P
var created moby.Container
w := progress.ContextWriter(ctx)
w.Event(progress.NewEvent(getContainerProgressName(replaced), progress.Working, "Recreate"))
err := s.apiClient().ContainerStop(ctx, replaced.ID, timeout)
timeoutInSecond := utils.DurationSecondToInt(timeout)
err := s.apiClient().ContainerStop(ctx, replaced.ID, containerType.StopOptions{Timeout: timeoutInSecond})
if err != nil {
return created, err
}
@@ -605,8 +616,9 @@ func (s *composeService) connectContainerToNetwork(ctx context.Context, id strin
ipv4Address = cfg.Ipv4Address
ipv6Address = cfg.Ipv6Address
ipam = &network.EndpointIPAMConfig{
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
LinkLocalIPs: cfg.LinkLocalIPs,
}
}
err := s.apiClient().NetworkConnect(ctx, netwrk, id, &network.EndpointSettings{

View File

@@ -23,12 +23,13 @@ import (
"testing"
"github.com/compose-spec/compose-go/types"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/golang/mock/gomock"
"gotest.tools/assert"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
)
func TestContainerName(t *testing.T) {
@@ -77,7 +78,9 @@ func TestServiceLinks(t *testing.T) {
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
s.Links = []string{"db"}
@@ -99,7 +102,9 @@ func TestServiceLinks(t *testing.T) {
defer mockCtrl.Finish()
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
s.Links = []string{"db:db"}
@@ -121,7 +126,9 @@ func TestServiceLinks(t *testing.T) {
defer mockCtrl.Finish()
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
s.Links = []string{"db:dbname"}
@@ -143,7 +150,9 @@ func TestServiceLinks(t *testing.T) {
defer mockCtrl.Finish()
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
s.Links = []string{"db:dbname"}
@@ -169,7 +178,9 @@ func TestServiceLinks(t *testing.T) {
defer mockCtrl.Finish()
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
s.Links = []string{}
@@ -203,7 +214,9 @@ func TestWaitDependencies(t *testing.T) {
apiClient := mocks.NewMockAPIClient(mockCtrl)
cli := mocks.NewMockCli(mockCtrl)
tested.dockerCli = cli
tested := composeService{
dockerCli: cli,
}
cli.EXPECT().Client().Return(apiClient).AnyTimes()
t.Run("should skip dependencies with scale 0", func(t *testing.T) {

View File

@@ -125,7 +125,8 @@ func prepareVolumes(p *types.Project) error {
p.Services[i].DependsOn = make(types.DependsOnConfig, len(dependServices))
}
for _, service := range p.Services {
if utils.StringContains(dependServices, service.Name) {
if utils.StringContains(dependServices, service.Name) &&
p.Services[i].DependsOn[service.Name].Condition == "" {
p.Services[i].DependsOn[service.Name] = types.ServiceDependency{
Condition: types.ServiceConditionStarted,
}
@@ -146,6 +147,9 @@ func prepareNetworks(project *types.Project) {
}
func prepareServicesDependsOn(p *types.Project) error {
allServices := types.Project{}
allServices.Services = p.AllServices()
for i, service := range p.Services {
var dependencies []string
networkDependency := getDependentServiceFromMode(service.NetworkMode)
@@ -178,20 +182,24 @@ func prepareServicesDependsOn(p *types.Project) error {
dependencies = append(dependencies, strings.Split(link, ":")[0])
}
for d := range service.DependsOn {
dependencies = append(dependencies, d)
}
if len(dependencies) == 0 {
continue
}
// Verify dependencies exist in the project, whether disabled or not
deps, err := allServices.GetServices(dependencies...)
if err != nil {
return err
}
if service.DependsOn == nil {
service.DependsOn = make(types.DependsOnConfig)
}
// Verify dependencies exist in the project, whether disabled or not
projAllServices := types.Project{}
projAllServices.Services = p.AllServices()
deps, err := projAllServices.GetServices(dependencies...)
if err != nil {
return err
}
for _, d := range deps {
if _, ok := service.DependsOn[d.Name]; !ok {
service.DependsOn[d.Name] = types.ServiceDependency{
@@ -306,8 +314,9 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
ipv4Address = config.Ipv4Address
ipv6Address = config.Ipv6Address
ipam = &network.EndpointIPAMConfig{
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
IPv4Address: ipv4Address,
IPv6Address: ipv6Address,
LinkLocalIPs: config.LinkLocalIPs,
}
}
networkConfig = &network.NetworkingConfig{
@@ -1146,7 +1155,7 @@ func (s *composeService) createVolume(ctx context.Context, volume types.VolumeCo
eventName := fmt.Sprintf("Volume %q", volume.Name)
w := progress.ContextWriter(ctx)
w.Event(progress.CreatingEvent(eventName))
_, err := s.apiClient().VolumeCreate(ctx, volume_api.VolumeCreateBody{
_, err := s.apiClient().VolumeCreate(ctx, volume_api.CreateOptions{
Labels: volume.Labels,
Name: volume.Name,
Driver: volume.Driver,

View File

@@ -96,6 +96,46 @@ func TestPrepareNetworkLabels(t *testing.T) {
}))
}
func TestPrepareVolumes(t *testing.T) {
t.Run("adds dependency condition if service depends on volume from another service", func(t *testing.T) {
project := composetypes.Project{
Name: "myProject",
Services: []composetypes.ServiceConfig{
{
Name: "aService",
VolumesFrom: []string{"anotherService"},
},
{
Name: "anotherService",
},
},
}
err := prepareVolumes(&project)
assert.NilError(t, err)
assert.Equal(t, project.Services[0].DependsOn["anotherService"].Condition, composetypes.ServiceConditionStarted)
})
t.Run("doesn't overwrite existing dependency condition", func(t *testing.T) {
project := composetypes.Project{
Name: "myProject",
Services: []composetypes.ServiceConfig{
{
Name: "aService",
VolumesFrom: []string{"anotherService"},
DependsOn: map[string]composetypes.ServiceDependency{
"anotherService": {Condition: composetypes.ServiceConditionHealthy},
},
},
{
Name: "anotherService",
},
},
}
err := prepareVolumes(&project)
assert.NilError(t, err)
assert.Equal(t, project.Services[0].DependsOn["anotherService"].Condition, composetypes.ServiceConditionHealthy)
})
}
func TestBuildContainerMountOptions(t *testing.T) {
project := composetypes.Project{
Name: "myProject",

View File

@@ -37,80 +37,110 @@ const (
ServiceStarted
)
type graphTraversalConfig struct {
type graphTraversal struct {
mu sync.Mutex
seen map[string]struct{}
extremityNodesFn func(*Graph) []*Vertex // leaves or roots
adjacentNodesFn func(*Vertex) []*Vertex // getParents or getChildren
filterAdjacentByStatusFn func(*Graph, string, ServiceStatus) []*Vertex // filterChildren or filterParents
targetServiceStatus ServiceStatus
adjacentServiceStatusToSkip ServiceStatus
visitorFn func(context.Context, string) error
}
var (
upDirectionTraversalConfig = graphTraversalConfig{
func upDirectionTraversal(visitorFn func(context.Context, string) error) *graphTraversal {
return &graphTraversal{
extremityNodesFn: leaves,
adjacentNodesFn: getParents,
filterAdjacentByStatusFn: filterChildren,
adjacentServiceStatusToSkip: ServiceStopped,
targetServiceStatus: ServiceStarted,
visitorFn: visitorFn,
}
downDirectionTraversalConfig = graphTraversalConfig{
}
func downDirectionTraversal(visitorFn func(context.Context, string) error) *graphTraversal {
return &graphTraversal{
extremityNodesFn: roots,
adjacentNodesFn: getChildren,
filterAdjacentByStatusFn: filterParents,
adjacentServiceStatusToSkip: ServiceStarted,
targetServiceStatus: ServiceStopped,
visitorFn: visitorFn,
}
)
}
// InDependencyOrder applies the function to the services of the project taking in account the dependency order
func InDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error) error {
return visit(ctx, project, upDirectionTraversalConfig, fn, ServiceStopped)
func InDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error, options ...func(*graphTraversal)) error {
graph, err := NewGraph(project.Services, ServiceStopped)
if err != nil {
return err
}
t := upDirectionTraversal(fn)
return t.visit(ctx, graph)
}
// InReverseDependencyOrder applies the function to the services of the project in reverse order of dependencies
func InReverseDependencyOrder(ctx context.Context, project *types.Project, fn func(context.Context, string) error) error {
return visit(ctx, project, downDirectionTraversalConfig, fn, ServiceStarted)
}
func visit(ctx context.Context, project *types.Project, traversalConfig graphTraversalConfig, fn func(context.Context, string) error, initialStatus ServiceStatus) error {
g := NewGraph(project.Services, initialStatus)
if b, err := g.HasCycles(); b {
graph, err := NewGraph(project.Services, ServiceStarted)
if err != nil {
return err
}
t := downDirectionTraversal(fn)
return t.visit(ctx, graph)
}
nodes := traversalConfig.extremityNodesFn(g)
func (t *graphTraversal) visit(ctx context.Context, g *Graph) error {
nodes := t.extremityNodesFn(g)
eg, _ := errgroup.WithContext(ctx)
eg.Go(func() error {
return run(ctx, g, eg, nodes, traversalConfig, fn)
})
eg, ctx := errgroup.WithContext(ctx)
t.run(ctx, g, eg, nodes)
return eg.Wait()
}
// Note: this could be `graph.walk` or whatever
func run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex, traversalConfig graphTraversalConfig, fn func(context.Context, string) error) error {
func (t *graphTraversal) run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex) {
for _, node := range nodes {
// Don't start this service yet if all of its children have
// not been started yet.
if len(traversalConfig.filterAdjacentByStatusFn(graph, node.Key, traversalConfig.adjacentServiceStatusToSkip)) != 0 {
if len(t.filterAdjacentByStatusFn(graph, node.Key, t.adjacentServiceStatusToSkip)) != 0 {
continue
}
node := node
if !t.consume(node.Key) {
// another worker already visited this node
continue
}
eg.Go(func() error {
err := fn(ctx, node.Service)
err := t.visitorFn(ctx, node.Service)
if err != nil {
return err
}
graph.UpdateStatus(node.Key, traversalConfig.targetServiceStatus)
graph.UpdateStatus(node.Key, t.targetServiceStatus)
return run(ctx, graph, eg, traversalConfig.adjacentNodesFn(node), traversalConfig, fn)
t.run(ctx, graph, eg, t.adjacentNodesFn(node))
return nil
})
}
}
return nil
func (t *graphTraversal) consume(nodeKey string) bool {
t.mu.Lock()
defer t.mu.Unlock()
if t.seen == nil {
t.seen = make(map[string]struct{})
}
if _, ok := t.seen[nodeKey]; ok {
return false
}
t.seen[nodeKey] = struct{}{}
return true
}
// Graph represents project as service dependencies
@@ -155,7 +185,7 @@ func (v *Vertex) GetChildren() []*Vertex {
}
// NewGraph returns the dependency graph of the services
func NewGraph(services types.Services, initialStatus ServiceStatus) *Graph {
func NewGraph(services types.Services, initialStatus ServiceStatus) (*Graph, error) {
graph := &Graph{
lock: sync.RWMutex{},
Vertices: map[string]*Vertex{},
@@ -171,7 +201,11 @@ func NewGraph(services types.Services, initialStatus ServiceStatus) *Graph {
}
}
return graph
if b, err := graph.HasCycles(); b {
return nil, err
}
return graph, nil
}
// NewVertex is the constructor function for the Vertex

View File

@@ -18,10 +18,13 @@ package compose
import (
"context"
"fmt"
"testing"
"github.com/compose-spec/compose-go/types"
"gotest.tools/v3/assert"
testify "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gotest.tools/assert"
)
var project = types.Project{
@@ -44,26 +47,251 @@ var project = types.Project{
},
}
func TestInDependencyUpCommandOrder(t *testing.T) {
order := make(chan string)
//nolint:errcheck, unparam
go InDependencyOrder(context.TODO(), &project, func(ctx context.Context, config string) error {
order <- config
func TestTraversalWithMultipleParents(t *testing.T) {
dependent := types.ServiceConfig{
Name: "dependent",
DependsOn: make(types.DependsOnConfig),
}
project := types.Project{
Services: []types.ServiceConfig{dependent},
}
for i := 1; i <= 100; i++ {
name := fmt.Sprintf("svc_%d", i)
dependent.DependsOn[name] = types.ServiceDependency{}
svc := types.ServiceConfig{Name: name}
project.Services = append(project.Services, svc)
}
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
svc := make(chan string, 10)
seen := make(map[string]int)
done := make(chan struct{})
go func() {
for service := range svc {
seen[service]++
}
done <- struct{}{}
}()
err := InDependencyOrder(ctx, &project, func(ctx context.Context, service string) error {
svc <- service
return nil
})
assert.Equal(t, <-order, "test3")
assert.Equal(t, <-order, "test2")
assert.Equal(t, <-order, "test1")
require.NoError(t, err, "Error during iteration")
close(svc)
<-done
testify.Len(t, seen, 101)
for svc, count := range seen {
assert.Equal(t, 1, count, "Service: %s", svc)
}
}
func TestInDependencyUpCommandOrder(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
var order []string
err := InDependencyOrder(ctx, &project, func(ctx context.Context, service string) error {
order = append(order, service)
return nil
})
require.NoError(t, err, "Error during iteration")
require.Equal(t, []string{"test3", "test2", "test1"}, order)
}
func TestInDependencyReverseDownCommandOrder(t *testing.T) {
order := make(chan string)
//nolint:errcheck, unparam
go InReverseDependencyOrder(context.TODO(), &project, func(ctx context.Context, config string) error {
order <- config
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
var order []string
err := InReverseDependencyOrder(ctx, &project, func(ctx context.Context, service string) error {
order = append(order, service)
return nil
})
assert.Equal(t, <-order, "test1")
assert.Equal(t, <-order, "test2")
assert.Equal(t, <-order, "test3")
require.NoError(t, err, "Error during iteration")
require.Equal(t, []string{"test1", "test2", "test3"}, order)
}
func TestBuildGraph(t *testing.T) {
testCases := []struct {
desc string
services types.Services
expectedVertices map[string]*Vertex
}{
{
desc: "builds graph with single service",
services: types.Services{
{
Name: "test",
DependsOn: types.DependsOnConfig{},
},
},
expectedVertices: map[string]*Vertex{
"test": {
Key: "test",
Service: "test",
Status: ServiceStopped,
Children: map[string]*Vertex{},
Parents: map[string]*Vertex{},
},
},
},
{
desc: "builds graph with two separate services",
services: types.Services{
{
Name: "test",
DependsOn: types.DependsOnConfig{},
},
{
Name: "another",
DependsOn: types.DependsOnConfig{},
},
},
expectedVertices: map[string]*Vertex{
"test": {
Key: "test",
Service: "test",
Status: ServiceStopped,
Children: map[string]*Vertex{},
Parents: map[string]*Vertex{},
},
"another": {
Key: "another",
Service: "another",
Status: ServiceStopped,
Children: map[string]*Vertex{},
Parents: map[string]*Vertex{},
},
},
},
{
desc: "builds graph with a service and a dependency",
services: types.Services{
{
Name: "test",
DependsOn: types.DependsOnConfig{
"another": types.ServiceDependency{},
},
},
{
Name: "another",
DependsOn: types.DependsOnConfig{},
},
},
expectedVertices: map[string]*Vertex{
"test": {
Key: "test",
Service: "test",
Status: ServiceStopped,
Children: map[string]*Vertex{
"another": {},
},
Parents: map[string]*Vertex{},
},
"another": {
Key: "another",
Service: "another",
Status: ServiceStopped,
Children: map[string]*Vertex{},
Parents: map[string]*Vertex{
"test": {},
},
},
},
},
{
desc: "builds graph with multiple dependency levels",
services: types.Services{
{
Name: "test",
DependsOn: types.DependsOnConfig{
"another": types.ServiceDependency{},
},
},
{
Name: "another",
DependsOn: types.DependsOnConfig{
"another_dep": types.ServiceDependency{},
},
},
{
Name: "another_dep",
DependsOn: types.DependsOnConfig{},
},
},
expectedVertices: map[string]*Vertex{
"test": {
Key: "test",
Service: "test",
Status: ServiceStopped,
Children: map[string]*Vertex{
"another": {},
},
Parents: map[string]*Vertex{},
},
"another": {
Key: "another",
Service: "another",
Status: ServiceStopped,
Children: map[string]*Vertex{
"another_dep": {},
},
Parents: map[string]*Vertex{
"test": {},
},
},
"another_dep": {
Key: "another_dep",
Service: "another_dep",
Status: ServiceStopped,
Children: map[string]*Vertex{},
Parents: map[string]*Vertex{
"another": {},
},
},
},
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
project := types.Project{
Services: tC.services,
}
graph, err := NewGraph(project.Services, ServiceStopped)
assert.NilError(t, err, fmt.Sprintf("failed to build graph for: %s", tC.desc))
for k, vertex := range graph.Vertices {
expected, ok := tC.expectedVertices[k]
assert.Equal(t, true, ok)
assert.Equal(t, true, isVertexEqual(*expected, *vertex))
}
})
}
}
func isVertexEqual(a, b Vertex) bool {
childrenEquality := true
for c := range a.Children {
if _, ok := b.Children[c]; !ok {
childrenEquality = false
}
}
parentEquality := true
for p := range a.Parents {
if _, ok := b.Parents[p]; !ok {
parentEquality = false
}
}
return a.Key == b.Key &&
a.Service == b.Service &&
childrenEquality &&
parentEquality
}

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