Compare commits

...

94 Commits

Author SHA1 Message Date
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
122 changed files with 1487 additions and 826 deletions

View File

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

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,209 @@ on:
description: 'To run with tmate enter "debug_enabled"'
required: false
default: "false"
env:
GO_VERSION: 1.18.4
GO_VERSION: "1.18.5" # for non sandboxed e2e tests
DESTDIR: "./bin"
DOCKER_CLI_VERSION: "20.10.17"
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-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 }}
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: 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:
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

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

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
bin/
dist/
/.vscode/

View File

@@ -1,5 +1,6 @@
run:
concurrency: 2
timeout: 10m
linters:
enable-all: false
disable-all: true
@@ -18,6 +19,7 @@ linters:
- lll
- misspell
- nakedret
- nolintlint
- staticcheck
- structcheck
- typecheck
@@ -27,7 +29,7 @@ linters:
- varcheck
linters-settings:
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,98 +15,166 @@
# 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.18.5
ARG XX_VERSION=1.1.2
ARG GOLANGCI_LINT_VERSION=v1.47.3
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 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.

View File

@@ -12,7 +12,11 @@
# 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)
GO_LDFLAGS ?= -s -w -X ${PKG}/internal.Version=${VERSION}
GO_BUILDTAGS ?= e2e,kube
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
@@ -22,8 +26,6 @@ ifeq ($(UNAME_S),Darwin)
MOBY_DOCKER=/Applications/Docker.app/Contents/Resources/bin/docker
endif
BINARY_FOLDER=$(shell pwd)/bin
GIT_TAG?=$(shell git describe --tags --match "v[0-9]*")
TEST_FLAGS?=
E2E_TEST?=
ifeq ($(E2E_TEST),)
@@ -31,15 +33,23 @@ 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" ./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
@@ -52,10 +62,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 +77,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 +113,19 @@ 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
pre-commit: validate check-dependencies lint compose-plugin test e2e-compose
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,9 @@
# 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)
![Docker Compose](logo.png?raw=true "Docker Compose Logo")

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

@@ -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 != "" {

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
@@ -354,8 +383,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

@@ -58,7 +58,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 {

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")
}
@@ -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,7 +38,7 @@ 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)
@@ -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 {

View File

@@ -43,7 +43,7 @@ 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)

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,7 +37,7 @@ 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)
@@ -43,20 +46,24 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
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,7 +44,7 @@ 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)

View File

@@ -44,13 +44,14 @@ func pauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
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,
})
}
@@ -74,12 +75,13 @@ func unpauseCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
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 {

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()
@@ -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 {

View File

@@ -36,7 +36,7 @@ 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)

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
@@ -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,7 +35,7 @@ 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)
@@ -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 {
@@ -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

@@ -43,12 +43,13 @@ func startCommand(p *projectOptions, backend api.Service) *cobra.Command {
}
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,
})
}

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

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

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)
}
}

126
docker-bake.hcl Normal file
View File

@@ -0,0 +1,126 @@
// 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.18.5"
}
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 "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

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

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:

19
go.mod
View File

@@ -5,11 +5,11 @@ go 1.18
require (
github.com/AlecAivazis/survey/v2 v2.3.5
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.6
github.com/compose-spec/compose-go v1.5.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/containerd/containerd v1.6.8
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f
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/docker/cli-docs-tool v0.5.0
@@ -19,21 +19,21 @@ require (
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/buildkit v0.10.4
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
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/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/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
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
gotest.tools/v3 v3.3.0
)
@@ -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.2.3-0.20220330195504-d132b287edc8 // 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
@@ -111,7 +111,7 @@ require (
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // 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
@@ -120,7 +120,6 @@ require (
google.golang.org/grpc v1.45.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

33
go.sum
View File

@@ -141,7 +141,7 @@ github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo=
github.com/Microsoft/hcsshim v0.9.4 h1:mnUj0ivWy6UzbB1uLFqKR6F+ZyiDc7j4iGgHTpO+5+I=
github.com/Microsoft/hcsshim/test v0.0.0-20200826032352-301c83a30e7c/go.mod h1:30A5igQ91GEmhYJF8TaRP79pMBOYynRsyOByfVV0dU4=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
@@ -270,8 +270,8 @@ github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e/go.mod h1:yMWuSON
github.com/cloudflare/cfssl v1.4.1 h1:vScfU2DrIUI9VPHBVeeAQ0q5A+9yshO1Gz+3QoUQiKw=
github.com/cnabio/cnab-go v0.23.4 h1:jplQcSnvFyQlD6swiqL3BmqRnhbnS+lc/EKdBLH9E80=
github.com/cnabio/cnab-go v0.23.4/go.mod h1:9EmgHR51LFqQStzaC+xHPJlkD4OPsF6Ev5Y8e/YHEns=
github.com/cnabio/cnab-to-oci v0.3.5 h1:X/8WVW1LjwGH4qD8rhovkmibW95CbItZdE39Velvg0k=
github.com/cnabio/cnab-to-oci v0.3.5/go.mod h1:7f86Z39HUg67wg8dZvxvFpW2pGDjK3RwbJAMJGxTXHQ=
github.com/cnabio/cnab-to-oci v0.3.6 h1:QVvy4WjQpGyf20xbbeYtRObX+pB8cWNuvvT/e4w1DoQ=
github.com/cnabio/cnab-to-oci v0.3.6/go.mod h1:AvVNl0Hh3VBk1zqeLdyE5S3bTQ5EsZPPF4mUUJYyy1Y=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -286,8 +286,8 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/compose-spec/compose-go v1.2.1/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
github.com/compose-spec/compose-go v1.3.0 h1:n5fSOUXQsfnCpn/lZBgNM3qEu1PDhvcbWrWXVBlUNmA=
github.com/compose-spec/compose-go v1.3.0/go.mod h1:l7RUULbFFLzlQHuxtJr7SVLyWdqEpbJEGTWCgcu6Eqw=
github.com/compose-spec/compose-go v1.5.0 h1:yOmYpIm13pYt2o+oKVe/JAD6o2Tv+eUyOcRhf0qF4fA=
github.com/compose-spec/compose-go v1.5.0/go.mod h1:l7RUULbFFLzlQHuxtJr7SVLyWdqEpbJEGTWCgcu6Eqw=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@@ -330,8 +330,8 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -339,8 +339,9 @@ github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cE
github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/continuity v0.2.2 h1:QSqfxcn8c+12slxwu00AtzXrsami0MJb/MQs9lOLHLA=
github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
github.com/containerd/continuity v0.2.3-0.20220330195504-d132b287edc8 h1:yGFEcFNMhze29DxAAB33v/1OMRYF/cM9iwwgV2P0ZrE=
github.com/containerd/continuity v0.2.3-0.20220330195504-d132b287edc8/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
@@ -448,8 +449,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M=
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb h1:oCCuuU3kMO3sjZH/p7LamvQNW9SWoT4yQuMGcdSxGAE=
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f h1:3NCYdjXycNd/Xn/iICZzmxkiDX1e1cjTHjbMAz+wRVk=
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/buildx v0.8.2 h1:dsd3F0hhmUydFX/KFrvbK81JvlTA4T3Iy0lwDJt4PsU=
github.com/docker/buildx v0.8.2/go.mod h1:5sMOfNwOmO2jy/MxBL4ySk2LoLIG1tQFu2EU8wbKa34=
@@ -970,8 +971,9 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
@@ -1014,14 +1016,14 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlKZIaiQ=
github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d h1:6pLVBJO3V/lMegbVD5kh2QrpZwqS4ZrxEm/MyifCPaY=
github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d/go.mod h1:WvwAZv8aRScHkqc/+X46cRC2CKMKpqcaX+pRvUTtPes=
github.com/moby/buildkit v0.10.4 h1:FvC+buO8isGpUFZ1abdSLdGHZVqg9sqI4BbFL8tlzP4=
github.com/moby/buildkit v0.10.4/go.mod h1:Yajz9vt1Zw5q9Pp4pdb3TCSUXJBIroIQGQ3TTs/sLug=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
github.com/moby/sys/mount v0.3.0 h1:bXZYMmq7DBQPwHRxH/MG+u9+XF90ZOwoXpHTOznMGp0=
github.com/moby/sys/mount v0.3.0/go.mod h1:U2Z3ur2rXPFrFmy4q6WMwWrBOAQGYtYTRVM8BIvzbwk=
github.com/moby/sys/mountinfo v0.1.0/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
github.com/moby/sys/mountinfo v0.1.3/go.mod h1:w2t2Avltqx8vE7gX5l+QiBKxODu2TX0+Syr3h52Tw4o=
@@ -1221,8 +1223,6 @@ github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUcc
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b h1:jUK33OXuZP/l6babJtnLo1qsGvq6G9so9KMflGAm4YA=
github.com/sanathkr/go-yaml v0.0.0-20170819195128-ed9d249f429b/go.mod h1:8458kAagoME2+LN5//WxE71ysZ3B7r22fdgb7qVmXSY=
github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
@@ -1796,8 +1796,9 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@@ -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
@@ -133,6 +133,8 @@ type StartOptions struct {
// 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 +143,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
@@ -193,6 +197,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 +209,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 +223,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 +284,7 @@ type ListOptions struct {
// PsOptions group options of the Ps API
type PsOptions struct {
Project *types.Project
All bool
Services []string
}
@@ -377,6 +390,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 (

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

@@ -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 {
@@ -214,10 +211,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
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 {

View File

@@ -29,7 +29,6 @@ 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/cli"
"github.com/docker/docker/pkg/archive"
@@ -40,6 +39,8 @@ import (
"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

View File

@@ -24,6 +24,8 @@ import (
"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"
@@ -33,7 +35,6 @@ import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/sanathkr/go-yaml"
)
// NewComposeService create a local implementation of the compose.Service API
@@ -172,26 +173,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

@@ -352,6 +352,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
@@ -605,8 +611,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

@@ -146,6 +146,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 +181,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 +313,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{

View File

@@ -21,7 +21,7 @@ import (
"testing"
"github.com/compose-spec/compose-go/types"
"gotest.tools/v3/assert"
"github.com/stretchr/testify/require"
)
var project = types.Project{
@@ -45,25 +45,27 @@ 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
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
})
assert.Equal(t, <-order, "test3")
assert.Equal(t, <-order, "test2")
assert.Equal(t, <-order, "test1")
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)
}

View File

@@ -45,8 +45,11 @@ func (s *composeService) down(ctx context.Context, projectName string, options a
w := progress.ContextWriter(ctx)
resourceToRemove := false
var containers Containers
containers, err := s.getContainers(ctx, projectName, oneOffInclude, true)
include := oneOffExclude
if options.RemoveOrphans {
include = oneOffInclude
}
containers, err := s.getContainers(ctx, projectName, include, true)
if err != nil {
return err
}

View File

@@ -40,7 +40,7 @@ func TestDown(t *testing.T) {
tested.dockerCli = cli
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return(
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(
[]moby.Container{
testContainer("service1", "123", false),
testContainer("service2", "456", false),
@@ -88,7 +88,7 @@ func TestDownRemoveOrphans(t *testing.T) {
tested.dockerCli = cli
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return(
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(true)).Return(
[]moby.Container{
testContainer("service1", "123", false),
testContainer("service2", "789", false),
@@ -125,7 +125,7 @@ func TestDownRemoveVolumes(t *testing.T) {
tested.dockerCli = cli
cli.EXPECT().Client().Return(api).AnyTimes()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return(
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(
[]moby.Container{testContainer("service1", "123", false)}, nil)
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
Return(volume.VolumeListOKBody{

View File

@@ -0,0 +1,68 @@
/*
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 (
"runtime"
"strings"
)
var (
// isCaseInsensitiveEnvVars is true on platforms where environment variable names are treated case-insensitively.
isCaseInsensitiveEnvVars = (runtime.GOOS == "windows")
)
// envResolver returns resolver for environment variables suitable for the current platform.
// Expected to be used with `MappingWithEquals.Resolve`.
// Updates in `environment` may not be reflected.
func envResolver(environment map[string]string) func(string) (string, bool) {
return envResolverWithCase(environment, isCaseInsensitiveEnvVars)
}
// envResolverWithCase returns resolver for environment variables with the specified case-sensitive condition.
// Expected to be used with `MappingWithEquals.Resolve`.
// Updates in `environment` may not be reflected.
func envResolverWithCase(environment map[string]string, caseInsensitive bool) func(string) (string, bool) {
if environment == nil {
return func(s string) (string, bool) {
return "", false
}
}
if !caseInsensitive {
return func(s string) (string, bool) {
v, ok := environment[s]
return v, ok
}
}
// variable names must be treated case-insensitively.
// Resolves in this way:
// * Return the value if its name matches with the passed name case-sensitively.
// * Otherwise, return the value if its lower-cased name matches lower-cased passed name.
// * The value is indefinite if multiple variable matches.
loweredEnvironment := make(map[string]string, len(environment))
for k, v := range environment {
loweredEnvironment[strings.ToLower(k)] = v
}
return func(s string) (string, bool) {
v, ok := environment[s]
if ok {
return v, ok
}
v, ok = loweredEnvironment[strings.ToLower(s)]
return v, ok
}
}

View File

@@ -0,0 +1,115 @@
/*
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 (
"testing"
"gotest.tools/assert"
)
func Test_EnvResolverWithCase(t *testing.T) {
tests := []struct {
name string
environment map[string]string
caseInsensitive bool
search string
expectedValue string
expectedOk bool
}{
{
name: "case sensitive/case match",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: false,
search: "Env1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case sensitive/case unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: false,
search: "ENV1",
expectedValue: "",
expectedOk: false,
},
{
name: "case sensitive/nil environment",
environment: nil,
caseInsensitive: false,
search: "Env1",
expectedValue: "",
expectedOk: false,
},
{
name: "case insensitive/case match",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "Env1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case insensitive/case unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "ENV1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case insensitive/unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "Env3",
expectedValue: "",
expectedOk: false,
},
{
name: "case insensitive/nil environment",
environment: nil,
caseInsensitive: true,
search: "Env1",
expectedValue: "",
expectedOk: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
f := envResolverWithCase(test.environment, test.caseInsensitive)
v, ok := f(test.search)
assert.Equal(t, v, test.expectedValue)
assert.Equal(t, ok, test.expectedOk)
})
}
}

View File

@@ -23,7 +23,7 @@ import (
"github.com/opencontainers/go-digest"
)
// ServiceHash compute configuration has for a service
// ServiceHash computes the configuration hash for a service.
func ServiceHash(o types.ServiceConfig) (string, error) {
// remove the Build config when generating the service hash
o.Build = nil

View File

@@ -45,6 +45,17 @@ func (s *composeService) kill(ctx context.Context, projectName string, options a
return err
}
project := options.Project
if project == nil {
project, err = s.getProjectWithResources(ctx, containers, projectName)
if err != nil {
return err
}
}
if !options.RemoveOrphans {
containers = containers.filter(isService(project.ServiceNames()...))
}
if len(containers) == 0 {
fmt.Fprintf(s.stderr(), "no container to kill")
}

View File

@@ -18,12 +18,14 @@ package compose
import (
"context"
"fmt"
"path/filepath"
"strings"
"testing"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
"github.com/golang/mock/gomock"
"gotest.tools/v3/assert"
@@ -51,6 +53,12 @@ func TestKillAll(t *testing.T) {
Filters: filters.NewArgs(projectFilter(name)),
}).Return(
[]moby.Container{testContainer("service1", "123", false), testContainer("service1", "456", false), testContainer("service2", "789", false)}, nil)
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
Return(volume.VolumeListOKBody{}, nil)
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
Return([]moby.NetworkResource{
{ID: "abc123", Name: "testProject_default"},
}, nil)
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "").Return(nil)
api.EXPECT().ContainerKill(anyCancellableContext(), "456", "").Return(nil)
api.EXPECT().ContainerKill(anyCancellableContext(), "789", "").Return(nil)
@@ -76,6 +84,12 @@ func TestKillSignal(t *testing.T) {
ctx := context.Background()
api.EXPECT().ContainerList(ctx, listOptions).Return([]moby.Container{testContainer(serviceName, "123", false)}, nil)
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
Return(volume.VolumeListOKBody{}, nil)
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
Return([]moby.NetworkResource{
{ID: "abc123", Name: "testProject_default"},
}, nil)
api.EXPECT().ContainerKill(anyCancellableContext(), "123", "SIGTERM").Return(nil)
err := tested.kill(ctx, name, compose.KillOptions{Services: []string{serviceName}, Signal: "SIGTERM"})
@@ -110,9 +124,15 @@ func anyCancellableContext() gomock.Matcher {
return gomock.AssignableToTypeOf(ctxWithCancel)
}
func projectFilterListOpt() moby.ContainerListOptions {
func projectFilterListOpt(withOneOff bool) moby.ContainerListOptions {
filter := filters.NewArgs(
projectFilter(strings.ToLower(testProject)),
)
if !withOneOff {
filter.Add("label", fmt.Sprintf("%s=False", compose.OneoffLabel))
}
return moby.ContainerListOptions{
Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject))),
Filters: filter,
All: true,
}
}

View File

@@ -21,11 +21,12 @@ import (
"io"
"strings"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
"golang.org/x/sync/errgroup"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/utils"
)
func (s *composeService) Logs(ctx context.Context, projectName string, consumer api.LogConsumer, options api.LogOptions) error {
@@ -95,7 +96,7 @@ func (s *composeService) logContainers(ctx context.Context, consumer api.LogCons
if err != nil {
return err
}
defer r.Close() //nolint errcheck
defer r.Close() //nolint:errcheck
name := getContainerNameWithoutProject(c)
w := utils.GetWriter(func(line string) {

View File

@@ -33,12 +33,16 @@ func (s *composeService) Pause(ctx context.Context, projectName string, options
})
}
func (s *composeService) pause(ctx context.Context, project string, options api.PauseOptions) error {
containers, err := s.getContainers(ctx, project, oneOffExclude, false, options.Services...)
func (s *composeService) pause(ctx context.Context, projectName string, options api.PauseOptions) error {
containers, err := s.getContainers(ctx, projectName, oneOffExclude, false, options.Services...)
if err != nil {
return err
}
if options.Project != nil {
containers = containers.filter(isService(options.Project.ServiceNames()...))
}
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
containers.forEach(func(container moby.Container) {
@@ -67,6 +71,10 @@ func (s *composeService) unPause(ctx context.Context, projectName string, option
return err
}
if options.Project != nil {
containers = containers.filter(isService(options.Project.ServiceNames()...))
}
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
containers.forEach(func(container moby.Container) {

View File

@@ -21,8 +21,6 @@ import (
"fmt"
"github.com/docker/compose/v2/pkg/api"
"github.com/sirupsen/logrus"
)
// logPrinter watch application containers an collect their logs
@@ -99,7 +97,6 @@ func (p *printer) Run(ctx context.Context, cascadeStop bool, exitCodeFrom string
exitCodeFrom = event.Service
}
if exitCodeFrom == event.Service {
logrus.Error(event.ExitCode)
exitCode = event.ExitCode
}
}

View File

@@ -37,6 +37,19 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options api
return nil, err
}
project := options.Project
if project == nil {
project, err = s.getProjectWithResources(ctx, containers, projectName)
if err != nil {
return nil, err
}
}
if len(options.Services) == 0 {
options.Services = project.ServiceNames()
}
containers = containers.filter(isService(options.Services...))
summary := make([]api.ContainerSummary, len(containers))
eg, ctx := errgroup.WithContext(ctx)
for i, container := range containers {

View File

@@ -26,6 +26,7 @@ import (
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
compose "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/mocks"
@@ -48,6 +49,8 @@ func TestPs(t *testing.T) {
c2, inspect2 := containerDetails("service1", "456", "running", "", 0)
c2.Ports = []moby.Port{{PublicPort: 80, PrivatePort: 90, IP: "localhost"}}
c3, inspect3 := containerDetails("service2", "789", "exited", "", 130)
api.EXPECT().VolumeList(ctx, gomock.Any()).Return(volume.VolumeListOKBody{}, nil)
api.EXPECT().NetworkList(ctx, gomock.Any()).Return([]moby.NetworkResource{}, nil)
api.EXPECT().ContainerList(ctx, listOpts).Return([]moby.Container{c1, c2, c3}, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "123").Return(inspect1, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "456").Return(inspect2, nil)

View File

@@ -21,6 +21,7 @@ import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
@@ -64,13 +65,16 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
eg, ctx := errgroup.WithContext(ctx)
var mustBuild []string
imagesBeingPulled := map[string]string{}
for _, service := range project.Services {
service := service
if service.Image == "" {
w.Event(progress.Event{
ID: service.Name,
Status: progress.Done,
Text: "Skipped",
Text: "Skipped - No image to be pulled",
})
continue
}
@@ -84,16 +88,27 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
})
continue
case types.PullPolicyMissing, types.PullPolicyIfNotPresent:
if _, ok := images[service.Image]; ok {
if imageAlreadyPresent(service.Image, images) {
w.Event(progress.Event{
ID: service.Name,
Status: progress.Done,
Text: "Exists",
Text: "Skipped - Image is already present locally",
})
continue
}
}
if s, ok := imagesBeingPulled[service.Image]; ok {
w.Event(progress.Event{
ID: service.Name,
Status: progress.Done,
Text: fmt.Sprintf("Skipped - Image is already being pulled by %v", s),
})
continue
}
imagesBeingPulled[service.Image] = service.Name
eg.Go(func() error {
_, err := s.pullServiceImage(ctx, service, info, s.configFile(), w, false)
if err != nil {
@@ -118,6 +133,19 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts
return err
}
func imageAlreadyPresent(serviceImage string, localImages map[string]string) bool {
normalizedImage, err := reference.ParseDockerRef(serviceImage)
if err != nil {
return false
}
tagged, ok := normalizedImage.(reference.NamedTagged)
if !ok {
return false
}
_, ok = localImages[serviceImage]
return ok && tagged.Tag() != "latest"
}
func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, info moby.Info, configFile driver.Auth, w progress.Writer, quietPull bool) (string, error) {
w.Event(progress.Event{
ID: service.Name,

View File

@@ -31,7 +31,7 @@ import (
func (s *composeService) Remove(ctx context.Context, projectName string, options api.RemoveOptions) error {
projectName = strings.ToLower(projectName)
containers, _, err := s.actualState(ctx, projectName, options.Services)
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true, options.Services...)
if err != nil {
if api.IsNotFoundError(err) {
fmt.Fprintln(s.stderr(), "No stopped containers")
@@ -40,6 +40,10 @@ func (s *composeService) Remove(ctx context.Context, projectName string, options
return err
}
if options.Project != nil {
containers = containers.filter(isService(options.Project.ServiceNames()...))
}
stoppedContainers := containers.filter(func(c moby.Container) bool {
return c.State != ContainerRunning
})

View File

@@ -34,15 +34,17 @@ func (s *composeService) Restart(ctx context.Context, projectName string, option
}
func (s *composeService) restart(ctx context.Context, projectName string, options api.RestartOptions) error {
observedState, err := s.getContainers(ctx, projectName, oneOffExclude, true)
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
if err != nil {
return err
}
project, err := s.projectFromName(observedState, projectName, options.Services...)
if err != nil {
return err
project := options.Project
if project == nil {
project, err = s.getProjectWithResources(ctx, containers, projectName)
if err != nil {
return err
}
}
if len(options.Services) == 0 {
@@ -50,12 +52,12 @@ func (s *composeService) restart(ctx context.Context, projectName string, option
}
w := progress.ContextWriter(ctx)
err = InDependencyOrder(ctx, project, func(c context.Context, service string) error {
return InDependencyOrder(ctx, project, func(c context.Context, service string) error {
if !utils.StringContains(options.Services, service) {
return nil
}
eg, ctx := errgroup.WithContext(ctx)
for _, container := range observedState.filter(isService(service)) {
for _, container := range containers.filter(isService(service)) {
container := container
eg.Go(func() error {
eventName := getContainerProgressName(container)
@@ -69,8 +71,4 @@ func (s *composeService) restart(ctx context.Context, projectName string, option
}
return eg.Wait()
})
if err != nil {
return err
}
return nil
}

View File

@@ -116,7 +116,7 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts
if len(opts.Environment) > 0 {
cmdEnv := types.NewMappingWithEquals(opts.Environment)
serviceOverrideEnv := cmdEnv.Resolve(func(s string) (string, bool) {
v, ok := project.Environment[s]
v, ok := envResolver(project.Environment)(s)
return v, ok
}).RemoveEmpty()
service.Environment.OverrideBy(serviceOverrideEnv)

View File

@@ -22,6 +22,7 @@ import (
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress"
"github.com/docker/compose/v2/pkg/utils"
)
func (s *composeService) Stop(ctx context.Context, projectName string, options api.StopOptions) error {
@@ -31,15 +32,28 @@ func (s *composeService) Stop(ctx context.Context, projectName string, options a
}
func (s *composeService) stop(ctx context.Context, projectName string, options api.StopOptions) error {
w := progress.ContextWriter(ctx)
containers, project, err := s.actualState(ctx, projectName, options.Services)
containers, err := s.getContainers(ctx, projectName, oneOffExclude, true)
if err != nil {
return err
}
project := options.Project
if project == nil {
project, err = s.getProjectWithResources(ctx, containers, projectName)
if err != nil {
return err
}
}
if len(options.Services) == 0 {
options.Services = project.ServiceNames()
}
w := progress.ContextWriter(ctx)
return InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error {
containersToStop := containers.filter(isService(service)).filter(isNotOneOff)
return s.stopContainers(ctx, w, containersToStop, options.Timeout)
if !utils.StringContains(options.Services, service) {
return nil
}
return s.stopContainers(ctx, w, containers.filter(isService(service)).filter(isNotOneOff), options.Timeout)
})
}

View File

@@ -26,6 +26,8 @@ import (
"github.com/docker/compose/v2/pkg/mocks"
moby "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
"github.com/golang/mock/gomock"
"gotest.tools/v3/assert"
)
@@ -40,12 +42,16 @@ func TestStopTimeout(t *testing.T) {
cli.EXPECT().Client().Return(api).AnyTimes()
ctx := context.Background()
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt()).Return(
api.EXPECT().ContainerList(gomock.Any(), projectFilterListOpt(false)).Return(
[]moby.Container{
testContainer("service1", "123", false),
testContainer("service1", "456", false),
testContainer("service2", "789", false),
}, nil)
api.EXPECT().VolumeList(gomock.Any(), filters.NewArgs(projectFilter(strings.ToLower(testProject)))).
Return(volume.VolumeListOKBody{}, nil)
api.EXPECT().NetworkList(gomock.Any(), moby.NetworkListOptions{Filters: filters.NewArgs(projectFilter(strings.ToLower(testProject)))}).
Return([]moby.NetworkResource{}, nil)
timeout := time.Duration(2) * time.Second
api.EXPECT().ContainerStop(gomock.Any(), "123", &timeout).Return(nil)

View File

@@ -61,12 +61,12 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
go func() {
<-signalChan
s.Kill(ctx, project.Name, api.KillOptions{ //nolint:errcheck
Services: project.ServiceNames(),
Services: options.Create.Services,
})
}()
return s.Stop(ctx, project.Name, api.StopOptions{
Services: project.ServiceNames(),
Services: options.Create.Services,
})
})
}

46
pkg/e2e/assert.go Normal file
View File

@@ -0,0 +1,46 @@
/*
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 e2e
import (
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
// RequireServiceState ensures that the container is in the expected state
// (running or exited).
func RequireServiceState(t testing.TB, cli *CLI, service string, state string) {
t.Helper()
psRes := cli.RunDockerComposeCmd(t, "ps", "--format=json", service)
var psOut []map[string]interface{}
require.NoError(t, json.Unmarshal([]byte(psRes.Stdout()), &psOut),
"Invalid `compose ps` JSON output")
for _, svc := range psOut {
require.Equal(t, service, svc["Service"],
"Found ps output for unexpected service")
require.Equalf(t,
strings.ToLower(state),
strings.ToLower(svc["State"].(string)),
"Service %q (%s) not in expected state",
service, svc["Name"],
)
}
}

66
pkg/e2e/buffer.go Normal file
View File

@@ -0,0 +1,66 @@
/*
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 e2e
import (
"bytes"
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
)
type lockedBuffer struct {
mu sync.Mutex
buf bytes.Buffer
}
func (l *lockedBuffer) Read(p []byte) (n int, err error) {
l.mu.Lock()
defer l.mu.Unlock()
return l.buf.Read(p)
}
func (l *lockedBuffer) Write(p []byte) (n int, err error) {
l.mu.Lock()
defer l.mu.Unlock()
return l.buf.Write(p)
}
func (l *lockedBuffer) String() string {
l.mu.Lock()
defer l.mu.Unlock()
return l.buf.String()
}
func (l *lockedBuffer) RequireEventuallyContains(t testing.TB, v string) {
t.Helper()
var bufContents strings.Builder
require.Eventuallyf(t, func() bool {
l.mu.Lock()
defer l.mu.Unlock()
if _, err := l.buf.WriteTo(&bufContents); err != nil {
require.FailNowf(t, "Failed to copy from buffer",
"Error: %v", err)
}
return strings.Contains(bufContents.String(), v)
}, 2*time.Second, 20*time.Millisecond,
"Buffer did not contain %q\n============\n%s\n============",
v, &bufContents)
}

View File

@@ -34,7 +34,7 @@ func TestEnvPriority(t *testing.T) {
})
// Full options activated
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected (From environment patched by --env-file)
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected (From OS Environment)
// 2. Compose File (service::environment section)
// 3. Compose File (service::env_file section file)
// 4. Container Image ENV directive
@@ -45,7 +45,7 @@ func TestEnvPriority(t *testing.T) {
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
cmd.Env = append(cmd.Env, "WHEREAMI=shell")
res := icmd.RunCmd(cmd)
assert.Equal(t, strings.TrimSpace(res.Stdout()), "override")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
})
// Full options activated
@@ -63,7 +63,7 @@ func TestEnvPriority(t *testing.T) {
})
// No Compose file, all other options
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected (From environment patched by --env-file)
// 1. Command Line (docker compose run --env <KEY[=VAL]>) <-- Result expected (From OS Environment)
// 2. Compose File (service::environment section)
// 3. Compose File (service::env_file section file)
// 4. Container Image ENV directive
@@ -74,7 +74,7 @@ func TestEnvPriority(t *testing.T) {
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
cmd.Env = append(cmd.Env, "WHEREAMI=shell")
res := icmd.RunCmd(cmd)
assert.Equal(t, strings.TrimSpace(res.Stdout()), "override")
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
})
// No Compose file, all other options with env variable from OS environment

View File

@@ -79,7 +79,7 @@ func TestLocalComposeRun(t *testing.T) {
})
t.Run("down", func(t *testing.T) {
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down")
c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/compose.yaml", "down", "--remove-orphans")
res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout())
})
@@ -121,6 +121,7 @@ func TestLocalComposeRun(t *testing.T) {
c.Env = append(c.Env, "COMPOSE_REMOVE_ORPHANS=True")
})
res := c.RunDockerCmd(t, "ps", "--all")
assert.Assert(t, !strings.Contains(res.Stdout(), "run-test"), res.Stdout())
})

View File

@@ -49,7 +49,7 @@ func TestLocalComposeUp(t *testing.T) {
assert.Assert(t, strings.Contains(output, `"word":`))
res = c.RunDockerCmd(t, "network", "ls")
res.Assert(t, icmd.Expected{Out: projectName + "-default"})
res.Assert(t, icmd.Expected{Out: projectName + "_default"})
})
t.Run("top", func(t *testing.T) {
@@ -74,7 +74,7 @@ func TestLocalComposeUp(t *testing.T) {
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.service": "web"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version":`})
res = c.RunDockerCmd(t, "network", "inspect", projectName+"-default")
res = c.RunDockerCmd(t, "network", "inspect", projectName+"_default")
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.network": "default"`})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.project": `})
res.Assert(t, icmd.Expected{Out: `"com.docker.compose.version": `})
@@ -119,22 +119,12 @@ func TestLocalComposeUp(t *testing.T) {
})
}
func TestComposePull(t *testing.T) {
c := NewParallelCLI(t)
res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/simple-composefile", "pull")
output := res.Combined()
assert.Assert(t, strings.Contains(output, "simple Pulled"))
assert.Assert(t, strings.Contains(output, "another Pulled"))
}
func TestDownComposefileInParentFolder(t *testing.T) {
c := NewParallelCLI(t)
tmpFolder, err := os.MkdirTemp("fixtures/simple-composefile", "test-tmp")
assert.NilError(t, err)
defer os.Remove(tmpFolder) // nolint: errcheck
defer os.Remove(tmpFolder) //nolint:errcheck
projectName := filepath.Base(tmpFolder)
res := c.RunDockerComposeCmd(t, "--project-directory", tmpFolder, "up", "-d")
@@ -241,6 +231,6 @@ func TestConvert(t *testing.T) {
default: null
networks:
default:
name: compose-e2e-convert-default`, filepath.Join(wd, "fixtures", "simple-build-test", "nginx-build")), ExitCode: 0})
name: compose-e2e-convert_default`, filepath.Join(wd, "fixtures", "simple-build-test", "nginx-build")), ExitCode: 0})
})
}

View File

@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.2
# syntax=docker/dockerfile:1
# Copyright 2020 Docker Compose CLI authors

View File

@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.2
# syntax=docker/dockerfile:1
# Copyright 2020 Docker Compose CLI authors

View File

@@ -0,0 +1,7 @@
services:
simple:
image: alpine:3.13
command: top
another:
image: alpine:3.13
command: top

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