diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml deleted file mode 100644 index f5e0db45..00000000 --- a/.github/workflows/artifacts.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Publish Artifacts -on: - issue_comment: - types: [created] -jobs: - publish-artifacts: - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/generate-artifacts') - runs-on: ubuntu-latest - steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 - with: - go-version: 1.18.3 - id: go - - - name: Checkout code into the Go module directory - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: go-${{ hashFiles('**/go.sum') }} - - - name: Build cross platform compose-plugin binaries - run: make -f builder.Makefile cross - - - name: Upload macos-amd64 binary - uses: actions/upload-artifact@v2 - with: - name: docker-compose-darwin-amd64 - path: ${{ github.workspace }}/bin/docker-compose-darwin-amd64 - - - name: Upload macos-arm64 binary - uses: actions/upload-artifact@v2 - with: - name: docker-compose-darwin-arm64 - path: ${{ github.workspace }}/bin/docker-compose-darwin-arm64 - - - name: Upload linux-amd64 binary - uses: actions/upload-artifact@v2 - with: - name: docker-compose-linux-amd64 - path: ${{ github.workspace }}/bin/docker-compose-linux-amd64 - - - name: Upload linux-ppc64le binary - uses: actions/upload-artifact@v2 - with: - name: docker-compose-linux-ppc64le - path: ${{ github.workspace }}/bin/docker-compose-linux-ppc64le - - - name: Upload windows-amd64 binary - uses: actions/upload-artifact@v2 - with: - name: docker-compose-windows-amd64.exe - path: ${{ github.workspace }}/bin/docker-compose-windows-amd64.exe - - - name: Update comment - uses: peter-evans/create-or-update-comment@v1 - with: - comment-id: ${{ github.event.comment.id }} - body: | - This PR can be tested using [binaries](https://github.com/docker/compose-cli/actions/runs/${{ github.run_id }}). - reactions: eyes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0b8af50..4f73eaac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,22 +11,22 @@ on: description: 'To run with tmate enter "debug_enabled"' required: false default: "false" - +env: + GO_VERSION: 1.18.5 + DOCKER_CLI_VERSION: 20.10.17 jobs: lint: name: Lint runs-on: ubuntu-latest - env: - GO111MODULE: "on" steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 - with: - go-version: 1.18.3 - id: go - - name: Checkout code into the Go module directory - uses: actions/checkout@v2 + 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 @@ -34,8 +34,9 @@ jobs: - name: Run golangci-lint env: BUILD_TAGS: e2e - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3 with: + version: v1.47.3 args: --timeout=180s # only on main branch, costs too much for the gain on every PR @@ -43,22 +44,15 @@ jobs: name: Validate cross build runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' - env: - GO111MODULE: "on" steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 - with: - go-version: 1.18.3 - id: go - - name: Checkout code into the Go module directory - uses: actions/checkout@v2 + uses: actions/checkout@v3 - - uses: actions/cache@v2 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v3 with: - path: ~/go/pkg/mod - key: go-${{ hashFiles('**/go.sum') }} + 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 @@ -68,28 +62,21 @@ jobs: build-plugin: name: Build and tests in plugin mode runs-on: ubuntu-latest - env: - GO111MODULE: "on" steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 + - 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: 1.18.3 - id: go + 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 + 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: Checkout code into the Go module directory - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: go-${{ hashFiles('**/go.sum') }} - - name: Test run: make -f builder.Makefile test @@ -104,28 +91,21 @@ jobs: build-standalone: name: Build and tests in standalone mode runs-on: ubuntu-latest - env: - GO111MODULE: "on" steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 + - 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: 1.18.3 - id: go + 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 + 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: Checkout code into the Go module directory - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: go-${{ hashFiles('**/go.sum') }} - - name: Build for local E2E env: BUILD_TAGS: e2e diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0971034c..9226f8c8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -40,6 +40,7 @@ jobs: uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 # v4.0.4 with: token: ${{ secrets.GHPAT_DOCS_DISPATCH }} + push-to-fork: docker-tools-robot/docker.github.io commit-message: Update Compose reference API to ${{ github.event.release.name }} signoff: true branch: dispatch/compose-api-reference-${{ github.event.release.name }} @@ -47,5 +48,4 @@ jobs: title: Update Compose reference API to ${{ github.event.release.name }} body: | Update the Compose reference API documentation to keep in sync with the latest release `${{ github.event.release.name }}` - labels: area/Compose draft: false diff --git a/.github/workflows/pr-closed.yml b/.github/workflows/pr-closed.yml deleted file mode 100644 index ab13ae12..00000000 --- a/.github/workflows/pr-closed.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index db520379..ea0556dc 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the latest code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 74805b21..002c105b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,32 +6,26 @@ on: tag: description: "Release Tag" required: true - +env: + GO_VERSION: 1.18.5 jobs: upload-release: runs-on: ubuntu-latest steps: - - name: Set up Go 1.18 - uses: actions/setup-go@v2 + - 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: 1.18.3 - id: go + 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 + curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.17.tgz | tar xz sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version - - name: Checkout code into the Go module directory - uses: actions/checkout@v2 - - - uses: actions/cache@v2 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Build run: make GIT_TAG=${{ github.event.inputs.tag }} -f builder.Makefile cross diff --git a/.golangci.yml b/.golangci.yml index 49e5801d..434b9287 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,6 +7,7 @@ linters: - deadcode - depguard - errcheck + - gocritic - gocyclo - gofmt - goimports @@ -32,6 +33,17 @@ linters-settings: # The io/ioutil package has been deprecated. # https://go.dev/doc/go1.16#ioutil - io/ioutil + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - opinionated + - style + disabled-checks: + - paramTypeCombine + - unnamedResult + - whyNoLint gocyclo: min-complexity: 16 lll: diff --git a/BUILDING.md b/BUILDING.md index a73fb53e..c51a1a3e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -34,15 +34,51 @@ make test If you need to update a golden file simply do `go test ./... -test.update-golden`. -### End to end tests +### End-to-end tests +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. -To run the end to end tests, run: + +Note that this requires a local Docker Engine to be running. + +#### Whole end-to-end tests suite + +To execute both CLI and standalone e2e tests, run : + +```console +make e2e +``` + +Or if you need to build the CLI, run: +```console +make build-and-e2e +``` + +#### Plugin end-to-end tests suite + +To execute CLI plugin e2e tests, run : ```console make e2e-compose ``` -Note that this requires a local Docker Engine to be running. +Or if you need to build the CLI, run: +```console +make build-and-e2e-compose +``` + +#### Standalone end-to-end tests suite + +To execute the standalone CLI e2e tests, run : + +```console +make e2e-compose-standalone +``` + +Or if you need to build the CLI, run: +```console +make build-and-e2e-compose-standalone +``` ## Releases diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55be2a92..2f9ebd84 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 diff --git a/Dockerfile b/Dockerfile index f0d96385..adfe3f96 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.2 +# syntax=docker/dockerfile:1 # Copyright 2020 Docker Compose CLI authors @@ -15,10 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG GO_VERSION=1.18.3-alpine -ARG GOLANGCI_LINT_VERSION=v1.40.1-alpine +ARG GO_VERSION=1.18.5-alpine +ARG GOLANGCI_LINT_VERSION=v1.47.3-alpine ARG PROTOC_GEN_GO_VERSION=v1.4.3 +FROM --platform=${BUILDPLATFORM} golangci/golangci-lint:${GOLANGCI_LINT_VERSION} AS local-golangci-lint + FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION} AS base WORKDIR /compose-cli RUN apk add --no-cache -vv \ @@ -34,7 +36,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \ FROM base AS lint ENV CGO_ENABLED=0 -COPY --from=golangci/golangci-lint /usr/bin/golangci-lint /usr/bin/golangci-lint +COPY --from=local-golangci-lint /usr/bin/golangci-lint /usr/bin/golangci-lint ARG BUILD_TAGS ARG GIT_TAG RUN --mount=target=. \ @@ -88,7 +90,7 @@ RUN --mount=target=. \ make -f builder.Makefile test FROM base AS check-license-headers -RUN go install github.com/kunalkushwaha/ltag@latest +RUN go install github.com/google/addlicense@latest RUN --mount=target=. \ make -f builder.Makefile check-license-headers diff --git a/Makefile b/Makefile index 0b36672c..2556adbf 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,12 @@ e2e-compose-standalone: ## Run End to end local tests in standalone mode. Set E2 docker-compose version 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 + +.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 + .PHONY: mocks mocks: mockgen -destination pkg/mocks/mock_docker_cli.go -package mocks github.com/docker/cli/cli/command Cli @@ -60,6 +66,9 @@ mocks: .PHONY: e2e 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 + .PHONY: cross cross: ## Compile the CLI for linux, darwin and windows @docker build . --target cross \ @@ -90,7 +99,7 @@ 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 \ + -f ./docs/Dockerfile \ --target update rm -rf ./docs/internal cp -R "$($@_TMP_OUT)"/out/* ./docs/ @@ -99,7 +108,7 @@ docs: ## generate documentation .PHONY: validate-docs validate-docs: ## validate the doc does not change @docker build . \ - -f ./docs/docs.Dockerfile \ + -f ./docs/Dockerfile \ --target validate .PHONY: check-dependencies diff --git a/cmd/compose/build.go b/cmd/compose/build.go index 298d3b67..b19b1b97 100644 --- a/cmd/compose/build.go +++ b/cmd/compose/build.go @@ -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 != "" { diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 84f24d8b..cfa5154a 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -136,6 +136,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 @@ -159,15 +177,15 @@ func (o *projectOptions) toProject(services []string, po ...cli.ProjectOptionsFn return nil, compose.WrapComposeError(err) } + if o.Compatibility || utils.StringToBool(options.Environment["COMPOSE_COMPATIBILITY"]) { + api.Separator = "_" + } + project, err := cli.ProjectFromOptions(options) if err != nil { return nil, compose.WrapComposeError(err) } - if o.Compatibility || utils.StringToBool(project.Environment["COMPOSE_COMPATIBILITY"]) { - compose.Separator = "_" - } - ef := o.EnvFile if ef != "" && !filepath.IsAbs(ef) { ef, err = filepath.Abs(ef) @@ -239,11 +257,11 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { verbose bool version bool ) - command := &cobra.Command{ + c := &cobra.Command{ Short: "Docker Compose", Use: PluginName, TraverseChildren: true, - // By default (no Run/RunE in parent command) for typos in subcommands, cobra displays the help of parent command but exit(0) ! + // By default (no Run/RunE in parent c) for typos in subcommands, cobra displays the help of parent c but exit(0) ! RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return cmd.Help() @@ -300,7 +318,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { }, } - command.AddCommand( + c.AddCommand( upCommand(&opts, backend), downCommand(&opts, backend), startCommand(&opts, backend), @@ -327,16 +345,16 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { createCommand(&opts, backend), copyCommand(&opts, backend), ) - command.Flags().SetInterspersed(false) - opts.addProjectFlags(command.Flags()) - command.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`) - command.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information") - command.Flags().MarkHidden("version") //nolint:errcheck - command.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`) - command.Flags().MarkHidden("no-ansi") //nolint:errcheck - command.Flags().BoolVar(&verbose, "verbose", false, "Show more output") - command.Flags().MarkHidden("verbose") //nolint:errcheck - return command + c.Flags().SetInterspersed(false) + opts.addProjectFlags(c.Flags()) + c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`) + c.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information") + c.Flags().MarkHidden("version") //nolint:errcheck + c.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`) + c.Flags().MarkHidden("no-ansi") //nolint:errcheck + c.Flags().BoolVar(&verbose, "verbose", false, "Show more output") + c.Flags().MarkHidden("verbose") //nolint:errcheck + return c } func setEnvWithDotEnv(prjOpts *projectOptions) error { @@ -354,10 +372,8 @@ func setEnvWithDotEnv(prjOpts *projectOptions) error { return err } for k, v := range envFromFile { - if _, ok := os.LookupEnv(k); !ok { - if err = os.Setenv(k, v); err != nil { - return err - } + if err := os.Setenv(k, v); err != nil { // overwrite the process env with merged OS + env file results + return err } } return nil diff --git a/cmd/compose/convert.go b/cmd/compose/convert.go index 0780eaba..79692620 100644 --- a/cmd/compose/convert.go +++ b/cmd/compose/convert.go @@ -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 { diff --git a/cmd/compose/create.go b/cmd/compose/create.go index 7ce8a185..a1b8d0fc 100644 --- a/cmd/compose/create.go +++ b/cmd/compose/create.go @@ -30,6 +30,8 @@ import ( type createOptions struct { Build bool noBuild bool + Pull string + pullChanged bool removeOrphans bool ignoreOrphans bool forceRecreate bool @@ -44,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") } @@ -56,6 +59,7 @@ func createCommand(p *projectOptions, backend api.Service) *cobra.Command { return nil }), RunE: p.WithProject(func(ctx context.Context, project *types.Project) error { + opts.Apply(project) return backend.Create(ctx, project, api.CreateOptions{ RemoveOrphans: opts.removeOrphans, IgnoreOrphans: opts.ignoreOrphans, @@ -71,6 +75,7 @@ func createCommand(p *projectOptions, backend api.Service) *cobra.Command { flags := cmd.Flags() flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.") flags.BoolVar(&opts.noBuild, "no-build", false, "Don't build an image, even if it's missing.") + flags.StringVar(&opts.Pull, "pull", "missing", `Pull image before running ("always"|"missing"|"never")`) flags.BoolVar(&opts.forceRecreate, "force-recreate", false, "Recreate containers even if their configuration and image haven't changed.") flags.BoolVar(&opts.noRecreate, "no-recreate", false, "If containers already exist, don't recreate them. Incompatible with --force-recreate.") return cmd @@ -105,6 +110,12 @@ func (opts createOptions) GetTimeout() *time.Duration { } func (opts createOptions) Apply(project *types.Project) { + if opts.pullChanged { + for i, service := range project.Services { + service.PullPolicy = opts.Pull + project.Services[i] = service + } + } if opts.Build { for i, service := range project.Services { if service.Build == nil { @@ -117,6 +128,9 @@ func (opts createOptions) Apply(project *types.Project) { if opts.noBuild { for i, service := range project.Services { service.Build = nil + if service.Image == "" { + service.Image = api.GetImageNameOrDefault(service, project.Name) + } project.Services[i] = service } } diff --git a/cmd/compose/down.go b/cmd/compose/down.go index e94aec1f..484b4e73 100644 --- a/cmd/compose/down.go +++ b/cmd/compose/down.go @@ -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,11 +65,10 @@ 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 { - switch name { - case "volume": + if name == "volume" { name = "volumes" logrus.Warn("--volume is deprecated, please use --volumes") } @@ -80,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 diff --git a/cmd/compose/events.go b/cmd/compose/events.go index 2f9e711a..f50605b4 100644 --- a/cmd/compose/events.go +++ b/cmd/compose/events.go @@ -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 { diff --git a/cmd/compose/exec.go b/cmd/compose/exec.go index 00faae6c..89b30ee8 100644 --- a/cmd/compose/exec.go +++ b/cmd/compose/exec.go @@ -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 { diff --git a/cmd/compose/images.go b/cmd/compose/images.go index eebef82e..208b8c95 100644 --- a/cmd/compose/images.go +++ b/cmd/compose/images.go @@ -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) diff --git a/cmd/compose/kill.go b/cmd/compose/kill.go index eb17f1f1..6a96dee0 100644 --- a/cmd/compose/kill.go +++ b/cmd/compose/kill.go @@ -34,7 +34,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) @@ -49,12 +49,12 @@ func killCommand(p *projectOptions, backend api.Service) *cobra.Command { } func runKill(ctx context.Context, backend api.Service, opts killOptions, services []string) error { - projectName, err := opts.toProjectName() + name, err := opts.toProjectName() if err != nil { return err } - return backend.Kill(ctx, projectName, api.KillOptions{ + return backend.Kill(ctx, name, api.KillOptions{ Services: services, Signal: opts.signal, }) diff --git a/cmd/compose/list.go b/cmd/compose/list.go index ac05dc1d..b2cbe221 100644 --- a/cmd/compose/list.go +++ b/cmd/compose/list.go @@ -39,19 +39,20 @@ type lsOptions struct { } func listCommand(backend api.Service) *cobra.Command { - opts := lsOptions{Filter: opts.NewFilterOpt()} + 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, opts) + return runList(ctx, backend, lsOpts) }), + Args: cobra.NoArgs, ValidArgsFunction: noCompletion(), } - lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") - lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs.") - lsCmd.Flags().Var(&opts.Filter, "filter", "Filter output based on conditions provided.") - lsCmd.Flags().BoolVarP(&opts.All, "all", "a", false, "Show all stopped Compose projects") + lsCmd.Flags().StringVar(&lsOpts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") + lsCmd.Flags().BoolVarP(&lsOpts.Quiet, "quiet", "q", false, "Only display IDs.") + lsCmd.Flags().Var(&lsOpts.Filter, "filter", "Filter output based on conditions provided.") + lsCmd.Flags().BoolVarP(&lsOpts.All, "all", "a", false, "Show all stopped Compose projects") return lsCmd } @@ -60,18 +61,18 @@ var acceptedListFilters = map[string]bool{ "name": true, } -func runList(ctx context.Context, backend api.Service, opts lsOptions) error { - filters := opts.Filter.Value() +func runList(ctx context.Context, backend api.Service, lsOpts lsOptions) error { + filters := lsOpts.Filter.Value() err := filters.Validate(acceptedListFilters) if err != nil { return err } - stackList, err := backend.List(ctx, api.ListOptions{All: opts.All}) + stackList, err := backend.List(ctx, api.ListOptions{All: lsOpts.All}) if err != nil { return err } - if opts.Quiet { + if lsOpts.Quiet { for _, s := range stackList { fmt.Println(s.Name) } @@ -90,7 +91,7 @@ func runList(ctx context.Context, backend api.Service, opts lsOptions) error { } view := viewFromStackList(stackList) - return formatter.Print(view, opts.Format, os.Stdout, func(w io.Writer) { + return formatter.Print(view, lsOpts.Format, os.Stdout, func(w io.Writer) { for _, stack := range view { _, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", stack.Name, stack.Status, stack.ConfigFiles) } diff --git a/cmd/compose/logs.go b/cmd/compose/logs.go index ce094698..ffe3dc2e 100644 --- a/cmd/compose/logs.go +++ b/cmd/compose/logs.go @@ -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) diff --git a/cmd/compose/pause.go b/cmd/compose/pause.go index f51f47c7..9afbcaec 100644 --- a/cmd/compose/pause.go +++ b/cmd/compose/pause.go @@ -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, }) } diff --git a/cmd/compose/port.go b/cmd/compose/port.go index 6ffd6d1f..7c539210 100644 --- a/cmd/compose/port.go +++ b/cmd/compose/port.go @@ -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 { diff --git a/cmd/compose/ps.go b/cmd/compose/ps.go index 0c294998..17581aec 100644 --- a/cmd/compose/ps.go +++ b/cmd/compose/ps.go @@ -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, }) diff --git a/cmd/compose/pull.go b/cmd/compose/pull.go index 59e948ed..32897498 100644 --- a/cmd/compose/pull.go +++ b/cmd/compose/pull.go @@ -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 { diff --git a/cmd/compose/push.go b/cmd/compose/push.go index 7e84e4c1..ef4a53d0 100644 --- a/cmd/compose/push.go +++ b/cmd/compose/push.go @@ -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) diff --git a/cmd/compose/remove.go b/cmd/compose/remove.go index 8f0bbd21..2c115249 100644 --- a/cmd/compose/remove.go +++ b/cmd/compose/remove.go @@ -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, }) } diff --git a/cmd/compose/restart.go b/cmd/compose/restart.go index f691c31f..2bb8c8f3 100644 --- a/cmd/compose/restart.go +++ b/cmd/compose/restart.go @@ -35,8 +35,8 @@ func restartCommand(p *projectOptions, backend api.Service) *cobra.Command { projectOptions: p, } restartCmd := &cobra.Command{ - Use: "restart", - Short: "Restart containers", + 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, }) } diff --git a/cmd/compose/run.go b/cmd/compose/run.go index 39f47609..bf81ef52 100644 --- a/cmd/compose/run.go +++ b/cmd/compose/run.go @@ -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") diff --git a/cmd/compose/start.go b/cmd/compose/start.go index e9b67ae4..45da7612 100644 --- a/cmd/compose/start.go +++ b/cmd/compose/start.go @@ -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, }) } diff --git a/cmd/compose/stop.go b/cmd/compose/stop.go index 39861cd6..484bed82 100644 --- a/cmd/compose/stop.go +++ b/cmd/compose/stop.go @@ -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, }) } diff --git a/cmd/compose/up.go b/cmd/compose/up.go index 7a89e1dd..ca6b57f5 100644 --- a/cmd/compose/up.go +++ b/cmd/compose/up.go @@ -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") @@ -115,6 +115,7 @@ func upCommand(p *projectOptions, backend api.Service) *cobra.Command { flags.BoolVarP(&up.Detach, "detach", "d", false, "Detached mode: Run containers in the background") flags.BoolVar(&create.Build, "build", false, "Build images before starting containers.") flags.BoolVar(&create.noBuild, "no-build", false, "Don't build an image, even if it's missing.") + flags.StringVar(&create.Pull, "pull", "missing", `Pull image before running ("always"|"missing"|"never")`) flags.BoolVar(&create.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.") flags.StringArrayVar(&up.scale, "scale", []string{}, "Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.") flags.BoolVar(&up.noColor, "no-color", false, "Produce monochrome output.") @@ -219,18 +220,20 @@ func runUp(ctx context.Context, backend api.Service, createOptions createOptions func setServiceScale(project *types.Project, name string, replicas uint64) error { for i, s := range project.Services { - if s.Name == name { - service, err := project.GetService(name) - if err != nil { - return err - } - if service.Deploy == nil { - service.Deploy = &types.DeployConfig{} - } - service.Deploy.Replicas = &replicas - project.Services[i] = service - return nil + if s.Name != name { + continue } + + service, err := project.GetService(name) + if err != nil { + return err + } + if service.Deploy == nil { + service.Deploy = &types.DeployConfig{} + } + service.Deploy.Replicas = &replicas + project.Services[i] = service + return nil } return fmt.Errorf("unknown service %q", name) } diff --git a/cmd/compose/version.go b/cmd/compose/version.go index 30e0e753..18c7b359 100644 --- a/cmd/compose/version.go +++ b/cmd/compose/version.go @@ -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.MaximumNArgs(0), + 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() diff --git a/cmd/formatter/logs.go b/cmd/formatter/logs.go index 2cc9c84e..b5bc3736 100644 --- a/cmd/formatter/logs.go +++ b/cmd/formatter/logs.go @@ -27,6 +27,16 @@ import ( "github.com/docker/compose/v2/pkg/api" ) +// LogConsumer consume logs from services and format them +type logConsumer struct { + ctx context.Context + presenters sync.Map // map[string]*presenter + width int + writer io.Writer + color bool + prefix bool +} + // NewLogConsumer creates a new LogConsumer func NewLogConsumer(ctx context.Context, w io.Writer, color bool, prefix bool) api.LogConsumer { return &logConsumer{ @@ -79,14 +89,14 @@ 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) //nolint:errcheck } } func (l *logConsumer) Status(container, msg string) { p := l.getPresenter(container) s := p.colors(fmt.Sprintf("%s %s\n", container, msg)) - l.writer.Write([]byte(s)) // nolint:errcheck + l.writer.Write([]byte(s)) //nolint:errcheck } func (l *logConsumer) computeWidth() { @@ -101,16 +111,6 @@ func (l *logConsumer) computeWidth() { l.width = width + 1 } -// LogConsumer consume logs from services and format them -type logConsumer struct { - ctx context.Context - presenters sync.Map // map[string]*presenter - width int - writer io.Writer - color bool - prefix bool -} - type presenter struct { colors colorFunc name string diff --git a/docs/docs.Dockerfile b/docs/Dockerfile similarity index 96% rename from docs/docs.Dockerfile rename to docs/Dockerfile index 61657b7e..b2321760 100644 --- a/docs/docs.Dockerfile +++ b/docs/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.3-labs +# syntax=docker/dockerfile:1 # Copyright 2020 Docker Compose CLI authors @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG GO_VERSION=1.18.3 +ARG GO_VERSION=1.18.5 ARG FORMATS=md,yaml FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS docsgen diff --git a/docs/reference/compose.md b/docs/reference/compose.md index 46d3a1a7..e1b2c1fd 100644 --- a/docs/reference/compose.md +++ b/docs/reference/compose.md @@ -23,7 +23,7 @@ Docker Compose | [`ps`](compose_ps.md) | List containers | | [`pull`](compose_pull.md) | Pull service images | | [`push`](compose_push.md) | Push service images | -| [`restart`](compose_restart.md) | Restart containers | +| [`restart`](compose_restart.md) | Restart service containers | | [`rm`](compose_rm.md) | Removes stopped service containers | | [`run`](compose_run.md) | Run a one-off command on a service. | | [`start`](compose_start.md) | Start services | diff --git a/docs/reference/compose_convert.md b/docs/reference/compose_convert.md index 91ff89ea..2744cb98 100644 --- a/docs/reference/compose_convert.md +++ b/docs/reference/compose_convert.md @@ -5,7 +5,7 @@ Converts the compose file to platform's canonical format ### Aliases -`convert`, `config` +`docker compose convert`, `docker compose config` ### Options diff --git a/docs/reference/compose_create.md b/docs/reference/compose_create.md index 00123ba7..843d4235 100644 --- a/docs/reference/compose_create.md +++ b/docs/reference/compose_create.md @@ -11,6 +11,7 @@ Creates containers for a service. | `--force-recreate` | | | Recreate containers even if their configuration and image haven't changed. | | `--no-build` | | | Don't build an image, even if it's missing. | | `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. | +| `--pull` | `string` | `missing` | Pull image before running ("always"\|"missing"\|"never") | diff --git a/docs/reference/compose_down.md b/docs/reference/compose_down.md index 8864aa6e..2dd5f2f2 100644 --- a/docs/reference/compose_down.md +++ b/docs/reference/compose_down.md @@ -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. | diff --git a/docs/reference/compose_pull.md b/docs/reference/compose_pull.md index c081c228..edc3a155 100644 --- a/docs/reference/compose_pull.md +++ b/docs/reference/compose_pull.md @@ -61,4 +61,4 @@ $ docker compose pull db ⠹ f63c47038e66 Waiting 9.3s ⠹ 77a0c198cde5 Waiting 9.3s ⠹ c8752d5b785c Waiting 9.3s -``̀` +``` diff --git a/docs/reference/compose_restart.md b/docs/reference/compose_restart.md index 12326662..cc152b56 100644 --- a/docs/reference/compose_restart.md +++ b/docs/reference/compose_restart.md @@ -1,7 +1,7 @@ # docker compose restart -Restart containers +Restart service containers ### Options @@ -14,7 +14,7 @@ Restart containers ## Description -Restarts all stopped and running services. +Restarts all stopped and running services, or the specified services only. If you make changes to your `compose.yml` configuration, these changes are not reflected after running this command. For example, changes to environment variables (which are added diff --git a/docs/reference/compose_run.md b/docs/reference/compose_run.md index 3d616963..01be4664 100644 --- a/docs/reference/compose_run.md +++ b/docs/reference/compose_run.md @@ -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. | diff --git a/docs/reference/compose_up.md b/docs/reference/compose_up.md index 1a110f3f..2a883c53 100644 --- a/docs/reference/compose_up.md +++ b/docs/reference/compose_up.md @@ -21,6 +21,7 @@ Create and start containers | `--no-log-prefix` | | | Don't print prefix in logs. | | `--no-recreate` | | | If containers already exist, don't recreate them. Incompatible with --force-recreate. | | `--no-start` | | | Don't start the services after creating them. | +| `--pull` | `string` | `missing` | Pull image before running ("always"\|"missing"\|"never") | | `--quiet-pull` | | | Pull without printing progress information. | | `--remove-orphans` | | | Remove containers for services not defined in the Compose file. | | `-V`, `--renew-anon-volumes` | | | Recreate anonymous volumes instead of retrieving data from the previous containers. | diff --git a/docs/reference/docker_compose.yaml b/docs/reference/docker_compose.yaml index 1af2baab..acf60695 100644 --- a/docs/reference/docker_compose.yaml +++ b/docs/reference/docker_compose.yaml @@ -1,277 +1,277 @@ command: docker compose short: Docker Compose long: |- - You can use compose subcommand, `docker compose [-f ...] [options] [COMMAND] [ARGS...]`, to build and manage - multiple services in Docker containers. + You can use compose subcommand, `docker compose [-f ...] [options] [COMMAND] [ARGS...]`, to build and manage + multiple services in Docker containers. - ### Use `-f` to specify name and path of one or more Compose files - Use the `-f` flag to specify the location of a Compose configuration file. + ### Use `-f` to specify name and path of one or more Compose files + Use the `-f` flag to specify the location of a Compose configuration file. - #### Specifying multiple Compose files - You can supply multiple `-f` configuration files. When you supply multiple files, Compose combines them into a single - configuration. Compose builds the configuration in the order you supply the files. Subsequent files override and add - to their predecessors. + #### Specifying multiple Compose files + You can supply multiple `-f` configuration files. When you supply multiple files, Compose combines them into a single + configuration. Compose builds the configuration in the order you supply the files. Subsequent files override and add + to their predecessors. - For example, consider this command line: + For example, consider this command line: - ```console - $ docker compose -f docker-compose.yml -f docker-compose.admin.yml run backup_db - ``` + ```console + $ docker compose -f docker-compose.yml -f docker-compose.admin.yml run backup_db + ``` - The `docker-compose.yml` file might specify a `webapp` service. + The `docker-compose.yml` file might specify a `webapp` service. - ```yaml - services: - webapp: - image: examples/web - ports: - - "8000:8000" - volumes: - - "/data" - ``` - If the `docker-compose.admin.yml` also specifies this same service, any matching fields override the previous file. - New values, add to the `webapp` service configuration. + ```yaml + services: + webapp: + image: examples/web + ports: + - "8000:8000" + volumes: + - "/data" + ``` + If the `docker-compose.admin.yml` also specifies this same service, any matching fields override the previous file. + New values, add to the `webapp` service configuration. - ```yaml - services: - webapp: - build: . - environment: - - DEBUG=1 - ``` + ```yaml + services: + webapp: + build: . + environment: + - DEBUG=1 + ``` - When you use multiple Compose files, all paths in the files are relative to the first configuration file specified - with `-f`. You can use the `--project-directory` option to override this base path. + When you use multiple Compose files, all paths in the files are relative to the first configuration file specified + with `-f`. You can use the `--project-directory` option to override this base path. - Use a `-f` with `-` (dash) as the filename to read the configuration from stdin. When stdin is used all paths in the - configuration are relative to the current working directory. + Use a `-f` with `-` (dash) as the filename to read the configuration from stdin. When stdin is used all paths in the + configuration are relative to the current working directory. - The `-f` flag is optional. If you don’t provide this flag on the command line, Compose traverses the working directory - and its parent directories looking for a `compose.yaml` or `docker-compose.yaml` file. + The `-f` flag is optional. If you don’t provide this flag on the command line, Compose traverses the working directory + and its parent directories looking for a `compose.yaml` or `docker-compose.yaml` file. - #### Specifying a path to a single Compose file - You can use the `-f` flag to specify a path to a Compose file that is not located in the current directory, either - from the command line or by setting up a `COMPOSE_FILE` environment variable in your shell or in an environment file. + #### Specifying a path to a single Compose file + You can use the `-f` flag to specify a path to a Compose file that is not located in the current directory, either + from the command line or by setting up a `COMPOSE_FILE` environment variable in your shell or in an environment file. - For an example of using the `-f` option at the command line, suppose you are running the Compose Rails sample, and - have a `compose.yaml` file in a directory called `sandbox/rails`. You can use a command like `docker compose pull` to - get the postgres image for the db service from anywhere by using the `-f` flag as follows: + For an example of using the `-f` option at the command line, suppose you are running the Compose Rails sample, and + have a `compose.yaml` file in a directory called `sandbox/rails`. You can use a command like `docker compose pull` to + get the postgres image for the db service from anywhere by using the `-f` flag as follows: - ```console - $ docker compose -f ~/sandbox/rails/compose.yaml pull db - ``` + ```console + $ docker compose -f ~/sandbox/rails/compose.yaml pull db + ``` - ### Use `-p` to specify a project name + ### Use `-p` to specify a project name - Each configuration has a project name. If you supply a `-p` flag, you can specify a project name. If you don’t - specify the flag, Compose uses the current directory name. - Project name can also be set by `COMPOSE_PROJECT_NAME` environment variable. + Each configuration has a project name. If you supply a `-p` flag, you can specify a project name. If you don’t + specify the flag, Compose uses the current directory name. + Project name can also be set by `COMPOSE_PROJECT_NAME` environment variable. - Most compose subcommand can be ran without a compose file, just passing - project name to retrieve the relevant resources. + Most compose subcommand can be ran without a compose file, just passing + project name to retrieve the relevant resources. - ```console - $ docker compose -p my_project ps -a - NAME SERVICE STATUS PORTS - my_project_demo_1 demo running + ```console + $ docker compose -p my_project ps -a + NAME SERVICE STATUS PORTS + my_project_demo_1 demo running - $ docker compose -p my_project logs - demo_1 | PING localhost (127.0.0.1): 56 data bytes - demo_1 | 64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.095 ms - ``` + $ docker compose -p my_project logs + demo_1 | PING localhost (127.0.0.1): 56 data bytes + demo_1 | 64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.095 ms + ``` - ### Use profiles to enable optional services + ### Use profiles to enable optional services - Use `--profile` to specify one or more active profiles - Calling `docker compose --profile frontend up` will start the services with the profile `frontend` and services - without any specified profiles. - You can also enable multiple profiles, e.g. with `docker compose --profile frontend --profile debug up` the profiles `frontend` and `debug` will be enabled. + Use `--profile` to specify one or more active profiles + Calling `docker compose --profile frontend up` will start the services with the profile `frontend` and services + without any specified profiles. + You can also enable multiple profiles, e.g. with `docker compose --profile frontend --profile debug up` the profiles `frontend` and `debug` will be enabled. - Profiles can also be set by `COMPOSE_PROFILES` environment variable. + Profiles can also be set by `COMPOSE_PROFILES` environment variable. - ### Set up environment variables + ### Set up environment variables - You can set environment variables for various docker compose options, including the `-f`, `-p` and `--profiles` flags. + You can set environment variables for various docker compose options, including the `-f`, `-p` and `--profiles` flags. - Setting the `COMPOSE_FILE` environment variable is equivalent to passing the `-f` flag, - `COMPOSE_PROJECT_NAME` environment variable does the same for to the `-p` flag, - and so does `COMPOSE_PROFILES` environment variable for to the `--profiles` flag. + Setting the `COMPOSE_FILE` environment variable is equivalent to passing the `-f` flag, + `COMPOSE_PROJECT_NAME` environment variable does the same for to the `-p` flag, + and so does `COMPOSE_PROFILES` environment variable for to the `--profiles` flag. - If flags are explicitly set on command line, associated environment variable is ignored + If flags are explicitly set on command line, associated environment variable is ignored - Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned - containers for the project. + Setting the `COMPOSE_IGNORE_ORPHANS` environment variable to `true` will stop docker compose from detecting orphaned + containers for the project. usage: docker compose pname: docker plink: docker.yaml cname: -- docker compose build -- docker compose convert -- docker compose cp -- docker compose create -- docker compose down -- docker compose events -- docker compose exec -- docker compose images -- docker compose kill -- docker compose logs -- docker compose ls -- docker compose pause -- docker compose port -- docker compose ps -- docker compose pull -- docker compose push -- docker compose restart -- docker compose rm -- docker compose run -- docker compose start -- docker compose stop -- docker compose top -- docker compose unpause -- docker compose up -- docker compose version + - docker compose build + - docker compose convert + - docker compose cp + - docker compose create + - docker compose down + - docker compose events + - docker compose exec + - docker compose images + - docker compose kill + - docker compose logs + - docker compose ls + - docker compose pause + - docker compose port + - docker compose ps + - docker compose pull + - docker compose push + - docker compose restart + - docker compose rm + - docker compose run + - docker compose start + - docker compose stop + - docker compose top + - docker compose unpause + - docker compose up + - docker compose version clink: -- docker_compose_build.yaml -- docker_compose_convert.yaml -- docker_compose_cp.yaml -- docker_compose_create.yaml -- docker_compose_down.yaml -- docker_compose_events.yaml -- docker_compose_exec.yaml -- docker_compose_images.yaml -- docker_compose_kill.yaml -- docker_compose_logs.yaml -- docker_compose_ls.yaml -- docker_compose_pause.yaml -- docker_compose_port.yaml -- docker_compose_ps.yaml -- docker_compose_pull.yaml -- docker_compose_push.yaml -- docker_compose_restart.yaml -- docker_compose_rm.yaml -- docker_compose_run.yaml -- docker_compose_start.yaml -- docker_compose_stop.yaml -- docker_compose_top.yaml -- docker_compose_unpause.yaml -- docker_compose_up.yaml -- docker_compose_version.yaml + - docker_compose_build.yaml + - docker_compose_convert.yaml + - docker_compose_cp.yaml + - docker_compose_create.yaml + - docker_compose_down.yaml + - docker_compose_events.yaml + - docker_compose_exec.yaml + - docker_compose_images.yaml + - docker_compose_kill.yaml + - docker_compose_logs.yaml + - docker_compose_ls.yaml + - docker_compose_pause.yaml + - docker_compose_port.yaml + - docker_compose_ps.yaml + - docker_compose_pull.yaml + - docker_compose_push.yaml + - docker_compose_restart.yaml + - docker_compose_rm.yaml + - docker_compose_run.yaml + - docker_compose_start.yaml + - docker_compose_stop.yaml + - docker_compose_top.yaml + - docker_compose_unpause.yaml + - docker_compose_up.yaml + - docker_compose_version.yaml options: -- option: ansi - value_type: string - default_value: auto - description: | - Control when to print ANSI control characters ("never"|"always"|"auto") - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: compatibility - value_type: bool - default_value: "false" - description: Run compose in backward compatibility mode - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: env-file - value_type: string - description: Specify an alternate environment file. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: file - shorthand: f - value_type: stringArray - default_value: '[]' - description: Compose configuration files - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-ansi - value_type: bool - default_value: "false" - description: Do not print ANSI control characters (DEPRECATED) - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: profile - value_type: stringArray - default_value: '[]' - description: Specify a profile to enable - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: project-directory - value_type: string - description: |- - Specify an alternate working directory - (default: the path of the, first specified, Compose file) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: project-name - shorthand: p - value_type: string - description: Project name - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: verbose - value_type: bool - default_value: "false" - description: Show more output - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: version - shorthand: v - value_type: bool - default_value: "false" - description: Show the Docker Compose version information - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: workdir - value_type: string - description: |- - DEPRECATED! USE --project-directory INSTEAD. - Specify an alternate working directory - (default: the path of the, first specified, Compose file) - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: ansi + value_type: string + default_value: auto + description: | + Control when to print ANSI control characters ("never"|"always"|"auto") + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: compatibility + value_type: bool + default_value: "false" + description: Run compose in backward compatibility mode + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: env-file + value_type: string + description: Specify an alternate environment file. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: file + shorthand: f + value_type: stringArray + default_value: '[]' + description: Compose configuration files + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-ansi + value_type: bool + default_value: "false" + description: Do not print ANSI control characters (DEPRECATED) + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: profile + value_type: stringArray + default_value: '[]' + description: Specify a profile to enable + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: project-directory + value_type: string + description: |- + Specify an alternate working directory + (default: the path of the, first specified, Compose file) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: project-name + shorthand: p + value_type: string + description: Project name + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: verbose + value_type: bool + default_value: "false" + description: Show more output + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: version + shorthand: v + value_type: bool + default_value: "false" + description: Show the Docker Compose version information + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: workdir + value_type: string + description: |- + DEPRECATED! USE --project-directory INSTEAD. + Specify an alternate working directory + (default: the path of the, first specified, Compose file) + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_build.yaml b/docs/reference/docker_compose_build.yaml index 05c62bd3..efb0149b 100644 --- a/docs/reference/docker_compose_build.yaml +++ b/docs/reference/docker_compose_build.yaml @@ -1,132 +1,132 @@ command: docker compose build short: Build or rebuild services long: |- - Services are built once and then tagged, by default as `project_service`. + Services are built once and then tagged, by default as `project_service`. - If the Compose file specifies an - [image](https://github.com/compose-spec/compose-spec/blob/master/spec.md#image) name, - the image is tagged with that name, substituting any variables beforehand. See - [variable interpolation](https://github.com/compose-spec/compose-spec/blob/master/spec.md#interpolation). + If the Compose file specifies an + [image](https://github.com/compose-spec/compose-spec/blob/master/spec.md#image) name, + the image is tagged with that name, substituting any variables beforehand. See + [variable interpolation](https://github.com/compose-spec/compose-spec/blob/master/spec.md#interpolation). - 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...] + 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 [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: build-arg - value_type: stringArray - default_value: '[]' - description: Set build-time variables for services. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: compress - value_type: bool - default_value: "true" - description: Compress the build context using gzip. DEPRECATED - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: force-rm - value_type: bool - default_value: "true" - description: Always remove intermediate containers. DEPRECATED - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: memory - shorthand: m - value_type: string - description: | - Set memory limit for the build container. Not supported on buildkit yet. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-cache - value_type: bool - default_value: "false" - description: Do not use cache when building the image - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-rm - value_type: bool - default_value: "false" - description: | - Do not remove intermediate containers after a successful build. DEPRECATED - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: parallel - value_type: bool - default_value: "true" - description: Build images in parallel. DEPRECATED - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: progress - value_type: string - default_value: auto - description: Set type of progress output (auto, tty, plain, quiet) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: pull - value_type: bool - default_value: "false" - description: Always attempt to pull a newer version of the image. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Don't print anything to STDOUT - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: ssh - value_type: string - description: | - Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: build-arg + value_type: stringArray + default_value: '[]' + description: Set build-time variables for services. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: compress + value_type: bool + default_value: "true" + description: Compress the build context using gzip. DEPRECATED + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: force-rm + value_type: bool + default_value: "true" + description: Always remove intermediate containers. DEPRECATED + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: memory + shorthand: m + value_type: string + description: | + Set memory limit for the build container. Not supported on buildkit yet. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-cache + value_type: bool + default_value: "false" + description: Do not use cache when building the image + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-rm + value_type: bool + default_value: "false" + description: | + Do not remove intermediate containers after a successful build. DEPRECATED + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: parallel + value_type: bool + default_value: "true" + description: Build images in parallel. DEPRECATED + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: progress + value_type: string + default_value: auto + description: Set type of progress output (auto, tty, plain, quiet) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: pull + value_type: bool + default_value: "false" + description: Always attempt to pull a newer version of the image. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Don't print anything to STDOUT + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: ssh + value_type: string + description: | + Set SSH authentications used when building service images. (use 'default' for using your default SSH Agent) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_convert.yaml b/docs/reference/docker_compose_convert.yaml index 2c23e2e0..fec06277 100644 --- a/docs/reference/docker_compose_convert.yaml +++ b/docs/reference/docker_compose_convert.yaml @@ -1,126 +1,126 @@ command: docker compose convert -aliases: config +aliases: docker compose convert, docker compose config short: Converts the compose file to platform's canonical format long: |- - `docker compose convert` render the actual data model to be applied on target platform. When used with Docker engine, - it merges the Compose files set by `-f` flags, resolves variables in Compose file, and expands short-notation into - fully defined Compose model. + `docker compose convert` render the actual data model to be applied on target platform. When used with Docker engine, + it merges the Compose files set by `-f` flags, resolves variables in Compose file, and expands short-notation into + fully defined Compose model. - To allow smooth migration from docker-compose, this subcommand declares alias `docker compose config` -usage: docker compose convert SERVICES + To allow smooth migration from docker-compose, this subcommand declares alias `docker compose config` +usage: docker compose convert [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: format - value_type: string - default_value: yaml - description: 'Format the output. Values: [yaml | json]' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: hash - value_type: string - description: Print the service config hash, one per line. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: images - value_type: bool - default_value: "false" - description: Print the image names, one per line. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-interpolate - value_type: bool - default_value: "false" - description: Don't interpolate environment variables. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-normalize - value_type: bool - default_value: "false" - description: Don't normalize compose model. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: output - shorthand: o - value_type: string - description: Save to file (default to stdout) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: profiles - value_type: bool - default_value: "false" - description: Print the profile names, one per line. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Only validate the configuration, don't print anything. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: resolve-image-digests - value_type: bool - default_value: "false" - description: Pin image tags to digests. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: services - value_type: bool - default_value: "false" - description: Print the service names, one per line. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: volumes - value_type: bool - default_value: "false" - description: Print the volume names, one per line. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: format + value_type: string + default_value: yaml + description: 'Format the output. Values: [yaml | json]' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: hash + value_type: string + description: Print the service config hash, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: images + value_type: bool + default_value: "false" + description: Print the image names, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-interpolate + value_type: bool + default_value: "false" + description: Don't interpolate environment variables. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-normalize + value_type: bool + default_value: "false" + description: Don't normalize compose model. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: output + shorthand: o + value_type: string + description: Save to file (default to stdout) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: profiles + value_type: bool + default_value: "false" + description: Print the profile names, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Only validate the configuration, don't print anything. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: resolve-image-digests + value_type: bool + default_value: "false" + description: Pin image tags to digests. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: services + value_type: bool + default_value: "false" + description: Print the service names, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: volumes + value_type: bool + default_value: "false" + description: Print the volume names, one per line. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_cp.yaml b/docs/reference/docker_compose_cp.yaml index 9f338242..89e8da6a 100644 --- a/docs/reference/docker_compose_cp.yaml +++ b/docs/reference/docker_compose_cp.yaml @@ -1,54 +1,55 @@ command: docker compose cp short: Copy files/folders between a service container and the local filesystem long: Copy files/folders between a service container and the local filesystem -usage: "docker compose cp [OPTIONS] SERVICE:SRC_PATH DEST_PATH|-\n\tdocker compose - cp [OPTIONS] SRC_PATH|- SERVICE:DEST_PATH" +usage: |- + docker compose cp [OPTIONS] SERVICE:SRC_PATH DEST_PATH|- + docker compose cp [OPTIONS] SRC_PATH|- SERVICE:DEST_PATH pname: docker compose plink: docker_compose.yaml options: -- option: all - value_type: bool - default_value: "false" - description: Copy to all the containers of the service. - deprecated: true - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: archive - shorthand: a - value_type: bool - default_value: "false" - description: Archive mode (copy all uid/gid information) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: follow-link - shorthand: L - value_type: bool - default_value: "false" - description: Always follow symbol link in SRC_PATH - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: index - value_type: int - default_value: "0" - description: | - Index of the container if there are multiple instances of a service . - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: all + value_type: bool + default_value: "false" + description: Copy to all the containers of the service. + deprecated: true + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: archive + shorthand: a + value_type: bool + default_value: "false" + description: Archive mode (copy all uid/gid information) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: follow-link + shorthand: L + value_type: bool + default_value: "false" + description: Always follow symbol link in SRC_PATH + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: index + value_type: int + default_value: "0" + description: | + Index of the container if there are multiple instances of a service . + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_create.yaml b/docs/reference/docker_compose_create.yaml index f71ea7b7..814c5cc3 100644 --- a/docs/reference/docker_compose_create.yaml +++ b/docs/reference/docker_compose_create.yaml @@ -1,52 +1,62 @@ 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: -- option: build - value_type: bool - default_value: "false" - description: Build images before starting containers. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: force-recreate - value_type: bool - default_value: "false" - description: | - Recreate containers even if their configuration and image haven't changed. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-build - value_type: bool - default_value: "false" - description: Don't build an image, even if it's missing. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-recreate - value_type: bool - default_value: "false" - description: | - If containers already exist, don't recreate them. Incompatible with --force-recreate. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: build + value_type: bool + default_value: "false" + description: Build images before starting containers. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: force-recreate + value_type: bool + default_value: "false" + description: | + Recreate containers even if their configuration and image haven't changed. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-build + value_type: bool + default_value: "false" + description: Don't build an image, even if it's missing. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-recreate + value_type: bool + default_value: "false" + description: | + If containers already exist, don't recreate them. Incompatible with --force-recreate. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: pull + value_type: string + default_value: missing + description: Pull image before running ("always"|"missing"|"never") + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_down.yaml b/docs/reference/docker_compose_down.yaml index 95ed4c1f..9b4916bd 100644 --- a/docs/reference/docker_compose_down.yaml +++ b/docs/reference/docker_compose_down.yaml @@ -1,66 +1,66 @@ command: docker compose down short: Stop and remove containers, networks long: |- - Stops containers and removes containers, networks, volumes, and images created by `up`. + Stops containers and removes containers, networks, volumes, and images created by `up`. - By default, the only things removed are: + By default, the only things removed are: - - Containers for services defined in the Compose file - - Networks defined in the networks section of the Compose file - - The default network, if one is used + - Containers for services defined in the Compose file + - Networks defined in the networks section of the Compose file + - The default network, if one is used - Networks and volumes defined as external are never removed. + Networks and volumes defined as external are never removed. - Anonymous volumes are not removed by default. However, as they don’t 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 + Anonymous volumes are not removed by default. However, as they don’t 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 [OPTIONS] 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: rmi - value_type: string - description: | - Remove images used by services. "local" remove only images that don't have a custom tag ("local"|"all") - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: timeout - shorthand: t - value_type: int - default_value: "10" - description: Specify a shutdown timeout in seconds - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: volumes - shorthand: v - value_type: bool - default_value: "false" - description: | - Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - 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: rmi + value_type: string + description: | + Remove images used by services. "local" remove only images that don't have a custom tag ("local"|"all") + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: timeout + shorthand: t + value_type: int + default_value: "10" + description: Specify a shutdown timeout in seconds + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: volumes + shorthand: v + value_type: bool + default_value: "false" + description: | + Remove named volumes declared in the `volumes` section of the Compose file and anonymous volumes attached to containers. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_events.yaml b/docs/reference/docker_compose_events.yaml index 1f0f8250..f6a389ed 100644 --- a/docs/reference/docker_compose_events.yaml +++ b/docs/reference/docker_compose_events.yaml @@ -1,39 +1,39 @@ command: docker compose events short: Receive real time events from containers. long: |- - Stream container events for every container in the project. + Stream container events for every container in the project. - With the `--json` flag, a json object is printed one per line with the format: + With the `--json` flag, a json object is printed one per line with the format: - ```json - { - "time": "2015-11-20T18:01:03.615550", - "type": "container", - "action": "create", - "id": "213cf7...5fc39a", - "service": "web", - "attributes": { - "name": "application_web_1", - "image": "alpine:edge" - } - } - ``` + ```json + { + "time": "2015-11-20T18:01:03.615550", + "type": "container", + "action": "create", + "id": "213cf7...5fc39a", + "service": "web", + "attributes": { + "name": "application_web_1", + "image": "alpine:edge" + } + } + ``` - The events that can be received using this can be seen [here](/engine/reference/commandline/events/#object-types). -usage: docker compose events [options] [--] [SERVICE...] + The events that can be received using this can be seen [here](/engine/reference/commandline/events/#object-types). +usage: docker compose events [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: json - value_type: bool - default_value: "false" - description: Output events as a stream of json objects - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: json + value_type: bool + default_value: "false" + description: Output events as a stream of json objects + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_exec.yaml b/docs/reference/docker_compose_exec.yaml index 5f70743f..ba357ae8 100644 --- a/docs/reference/docker_compose_exec.yaml +++ b/docs/reference/docker_compose_exec.yaml @@ -1,111 +1,111 @@ command: docker compose exec short: Execute a command in a running container. long: |- - This is the equivalent of `docker exec` targeting a Compose service. + This is the equivalent of `docker exec` targeting a Compose service. - 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...] + 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] SERVICE COMMAND [ARGS...] pname: docker compose plink: docker_compose.yaml options: -- option: detach - shorthand: d - value_type: bool - default_value: "false" - description: 'Detached mode: Run command in the background.' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: env - shorthand: e - value_type: stringArray - default_value: '[]' - description: Set environment variables - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: index - value_type: int - default_value: "1" - description: | - index of the container if there are multiple instances of a service [default: 1]. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: interactive - shorthand: i - value_type: bool - default_value: "true" - description: Keep STDIN open even if not attached. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-TTY - shorthand: T - value_type: bool - default_value: "true" - description: | - Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: privileged - value_type: bool - default_value: "false" - description: Give extended privileges to the process. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: tty - shorthand: t - value_type: bool - default_value: "true" - description: Allocate a pseudo-TTY. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: user - shorthand: u - value_type: string - description: Run the command as this user. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: workdir - shorthand: w - value_type: string - description: Path to workdir directory for this command. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: detach + shorthand: d + value_type: bool + default_value: "false" + description: 'Detached mode: Run command in the background.' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: env + shorthand: e + value_type: stringArray + default_value: '[]' + description: Set environment variables + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: index + value_type: int + default_value: "1" + description: | + index of the container if there are multiple instances of a service [default: 1]. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: interactive + shorthand: i + value_type: bool + default_value: "true" + description: Keep STDIN open even if not attached. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-TTY + shorthand: T + value_type: bool + default_value: "true" + description: | + Disable pseudo-TTY allocation. By default `docker compose exec` allocates a TTY. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: privileged + value_type: bool + default_value: "false" + description: Give extended privileges to the process. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: tty + shorthand: t + value_type: bool + default_value: "true" + description: Allocate a pseudo-TTY. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: user + shorthand: u + value_type: string + description: Run the command as this user. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: workdir + shorthand: w + value_type: string + description: Path to workdir directory for this command. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_images.yaml b/docs/reference/docker_compose_images.yaml index 8e263aef..8e884518 100644 --- a/docs/reference/docker_compose_images.yaml +++ b/docs/reference/docker_compose_images.yaml @@ -1,21 +1,21 @@ 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: -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Only display IDs - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Only display IDs + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_kill.yaml b/docs/reference/docker_compose_kill.yaml index f9334782..c082c80c 100644 --- a/docs/reference/docker_compose_kill.yaml +++ b/docs/reference/docker_compose_kill.yaml @@ -1,26 +1,26 @@ command: docker compose kill short: Force stop service containers. long: |- - Forces running containers to stop by sending a `SIGKILL` signal. Optionally the signal can be passed, for example: + Forces running containers to stop by sending a `SIGKILL` signal. Optionally the signal can be passed, for example: - ```console - $ docker-compose kill -s SIGINT - ``` -usage: docker compose kill [options] [SERVICE...] + ```console + $ docker-compose kill -s SIGINT + ``` +usage: docker compose kill [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: signal - shorthand: s - value_type: string - default_value: SIGKILL - description: SIGNAL to send to the container. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: signal + shorthand: s + value_type: string + default_value: SIGKILL + description: SIGNAL to send to the container. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_logs.yaml b/docs/reference/docker_compose_logs.yaml index 2846bacc..c9afcc81 100644 --- a/docs/reference/docker_compose_logs.yaml +++ b/docs/reference/docker_compose_logs.yaml @@ -1,83 +1,83 @@ 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: -- option: follow - shorthand: f - value_type: bool - default_value: "false" - description: Follow log output. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-color - value_type: bool - default_value: "false" - description: Produce monochrome output. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-log-prefix - value_type: bool - default_value: "false" - description: Don't print prefix in logs. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: since - value_type: string - description: | - Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: tail - value_type: string - default_value: all - description: | - Number of lines to show from the end of the logs for each container. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: timestamps - shorthand: t - value_type: bool - default_value: "false" - description: Show timestamps. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: until - value_type: string - description: | - Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: follow + shorthand: f + value_type: bool + default_value: "false" + description: Follow log output. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-color + value_type: bool + default_value: "false" + description: Produce monochrome output. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-log-prefix + value_type: bool + default_value: "false" + description: Don't print prefix in logs. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: since + value_type: string + description: | + Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: tail + value_type: string + default_value: all + description: | + Number of lines to show from the end of the logs for each container. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: timestamps + shorthand: t + value_type: bool + default_value: "false" + description: Show timestamps. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: until + value_type: string + description: | + Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_ls.yaml b/docs/reference/docker_compose_ls.yaml index 97ce1364..e64081de 100644 --- a/docs/reference/docker_compose_ls.yaml +++ b/docs/reference/docker_compose_ls.yaml @@ -1,51 +1,51 @@ 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: -- option: all - shorthand: a - value_type: bool - default_value: "false" - description: Show all stopped Compose projects - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: filter - value_type: filter - description: Filter output based on conditions provided. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: format - value_type: string - default_value: pretty - description: 'Format the output. Values: [pretty | json].' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Only display IDs. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: all + shorthand: a + value_type: bool + default_value: "false" + description: Show all stopped Compose projects + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: filter + value_type: filter + description: Filter output based on conditions provided. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: format + value_type: string + default_value: pretty + description: 'Format the output. Values: [pretty | json].' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Only display IDs. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_pause.yaml b/docs/reference/docker_compose_pause.yaml index 95342fda..378ebb38 100644 --- a/docs/reference/docker_compose_pause.yaml +++ b/docs/reference/docker_compose_pause.yaml @@ -1,7 +1,7 @@ command: docker compose pause short: Pause services long: | - Pauses running containers of a service. They can be unpaused with `docker compose unpause`. + Pauses running containers of a service. They can be unpaused with `docker compose unpause`. usage: docker compose pause [SERVICE...] pname: docker compose plink: docker_compose.yaml diff --git a/docs/reference/docker_compose_port.yaml b/docs/reference/docker_compose_port.yaml index 739d3d7e..3655fa3a 100644 --- a/docs/reference/docker_compose_port.yaml +++ b/docs/reference/docker_compose_port.yaml @@ -1,30 +1,30 @@ 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: -- option: index - value_type: int - default_value: "1" - description: index of the container if service has multiple replicas - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: protocol - value_type: string - default_value: tcp - description: tcp or udp - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: index + value_type: int + default_value: "1" + description: index of the container if service has multiple replicas + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: protocol + value_type: string + default_value: tcp + description: tcp or udp + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_ps.yaml b/docs/reference/docker_compose_ps.yaml index 896f3069..4e40f6f7 100644 --- a/docs/reference/docker_compose_ps.yaml +++ b/docs/reference/docker_compose_ps.yaml @@ -1,170 +1,170 @@ command: docker compose ps short: List containers long: |- - Lists containers for a Compose project, with current status and exposed ports. - By default, both running and stopped containers are shown: + Lists containers for a Compose project, with current status and exposed ports. + By default, both running and stopped containers are shown: - ```console - $ docker compose ps - NAME COMMAND SERVICE STATUS PORTS - 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...] + ```console + $ docker compose ps + NAME COMMAND SERVICE STATUS PORTS + 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 [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: all - shorthand: a - value_type: bool - default_value: "false" - description: | - Show all stopped containers (including those created by the run command) - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: filter - value_type: string - description: 'Filter services by a property (supported filters: status).' - details_url: '#filter' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: format - value_type: string - default_value: pretty - description: 'Format the output. Values: [pretty | json]' - details_url: '#format' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Only display IDs - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: services - value_type: bool - default_value: "false" - description: Display services - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: status - value_type: stringArray - default_value: '[]' - description: | - Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited] - details_url: '#status' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: all + shorthand: a + value_type: bool + default_value: "false" + description: | + Show all stopped containers (including those created by the run command) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: filter + value_type: string + description: 'Filter services by a property (supported filters: status).' + details_url: '#filter' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: format + value_type: string + default_value: pretty + description: 'Format the output. Values: [pretty | json]' + details_url: '#format' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Only display IDs + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: services + value_type: bool + default_value: "false" + description: Display services + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: status + value_type: stringArray + default_value: '[]' + description: | + Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited] + details_url: '#status' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false examples: |- - ### Format the output (--format) {#format} + ### Format the output (--format) {#format} - By default, the `docker compose ps` command uses a table ("pretty") format to - show the containers. The `--format` flag allows you to specify alternative - presentations for the output. Currently supported options are `pretty` (default), - and `json`, which outputs information about the containers as a JSON array: + By default, the `docker compose ps` command uses a table ("pretty") format to + show the containers. The `--format` flag allows you to specify alternative + presentations for the output. Currently supported options are `pretty` (default), + and `json`, which outputs information about the containers as a JSON array: - ```console - $ docker compose ps --format json - [{"ID":"1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a","Name":"example-bar-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"bar","State":"exited","Health":"","ExitCode":0,"Publishers":null},{"ID":"f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0","Name":"example-foo-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"foo","State":"running","Health":"","ExitCode":0,"Publishers":[{"URL":"0.0.0.0","TargetPort":80,"PublishedPort":8080,"Protocol":"tcp"}]}] - ``` + ```console + $ docker compose ps --format json + [{"ID":"1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a","Name":"example-bar-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"bar","State":"exited","Health":"","ExitCode":0,"Publishers":null},{"ID":"f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0","Name":"example-foo-1","Command":"/docker-entrypoint.sh nginx -g 'daemon off;'","Project":"example","Service":"foo","State":"running","Health":"","ExitCode":0,"Publishers":[{"URL":"0.0.0.0","TargetPort":80,"PublishedPort":8080,"Protocol":"tcp"}]}] + ``` - The JSON output allows you to use the information in other tools for further - processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/){:target="_blank" rel="noopener" class="_"} - to pretty-print the JSON: + The JSON output allows you to use the information in other tools for further + processing, for example, using the [`jq` utility](https://stedolan.github.io/jq/){:target="_blank" rel="noopener" class="_"} + to pretty-print the JSON: - ```console - $ docker compose ps --format json | jq . - [ - { - "ID": "1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a", - "Name": "example-bar-1", - "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", - "Project": "example", - "Service": "bar", - "State": "exited", - "Health": "", - "ExitCode": 0, - "Publishers": null - }, - { - "ID": "f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0", - "Name": "example-foo-1", - "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", - "Project": "example", - "Service": "foo", - "State": "running", - "Health": "", - "ExitCode": 0, - "Publishers": [ - { - "URL": "0.0.0.0", - "TargetPort": 80, - "PublishedPort": 8080, - "Protocol": "tcp" - } - ] - } - ] - ``` + ```console + $ docker compose ps --format json | jq . + [ + { + "ID": "1553b0236cf4d2715845f053a4ee97042c4f9a2ef655731ee34f1f7940eaa41a", + "Name": "example-bar-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "bar", + "State": "exited", + "Health": "", + "ExitCode": 0, + "Publishers": null + }, + { + "ID": "f02a4efaabb67416e1ff127d51c4b5578634a0ad5743bd65225ff7d1909a3fa0", + "Name": "example-foo-1", + "Command": "/docker-entrypoint.sh nginx -g 'daemon off;'", + "Project": "example", + "Service": "foo", + "State": "running", + "Health": "", + "ExitCode": 0, + "Publishers": [ + { + "URL": "0.0.0.0", + "TargetPort": 80, + "PublishedPort": 8080, + "Protocol": "tcp" + } + ] + } + ] + ``` - ### Filter containers by status (--status) {#status} + ### Filter containers by status (--status) {#status} - Use the `--status` flag to filter the list of containers by status. For example, - to show only containers that are running, or only containers that have exited: + Use the `--status` flag to filter the list of containers by status. For example, + to show only containers that are running, or only containers that have exited: - ```console - $ docker compose ps --status=running - NAME COMMAND SERVICE STATUS PORTS - example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + ```console + $ docker compose ps --status=running + NAME COMMAND SERVICE STATUS PORTS + example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp - $ docker compose ps --status=exited - NAME COMMAND SERVICE STATUS PORTS - example-bar-1 "/docker-entrypoint.…" bar exited (0) - ``` + $ docker compose ps --status=exited + NAME COMMAND SERVICE STATUS PORTS + example-bar-1 "/docker-entrypoint.…" bar exited (0) + ``` - ### Filter containers by status (--filter) {#filter} + ### Filter containers by status (--filter) {#filter} - The [`--status` flag](#status) is a convenience shorthand for the `--filter status=` - flag. The example below is the equivalent to the example from the previous section, - this time using the `--filter` flag: + The [`--status` flag](#status) is a convenience shorthand for the `--filter status=` + flag. The example below is the equivalent to the example from the previous section, + this time using the `--filter` flag: - ```console - $ docker compose ps --filter status=running - NAME COMMAND SERVICE STATUS PORTS - example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp + ```console + $ docker compose ps --filter status=running + NAME COMMAND SERVICE STATUS PORTS + example-foo-1 "/docker-entrypoint.…" foo running 0.0.0.0:8080->80/tcp - $ docker compose ps --filter status=running - NAME COMMAND SERVICE STATUS PORTS - example-bar-1 "/docker-entrypoint.…" bar exited (0) - ``` + $ docker compose ps --filter status=running + NAME COMMAND SERVICE STATUS PORTS + example-bar-1 "/docker-entrypoint.…" bar exited (0) + ``` - The `docker compose ps` command currently only supports the `--filter status=` - option, but additional filter options may be added in future. + The `docker compose ps` command currently only supports the `--filter status=` + option, but additional filter options may be added in future. deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_pull.yaml b/docs/reference/docker_compose_pull.yaml index c7da031e..a06e8387 100644 --- a/docs/reference/docker_compose_pull.yaml +++ b/docs/reference/docker_compose_pull.yaml @@ -1,104 +1,104 @@ command: docker compose pull 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...] + 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 [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: ignore-pull-failures - value_type: bool - default_value: "false" - description: Pull what it can and ignores images with pull failures - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: include-deps - value_type: bool - default_value: "false" - description: Also pull services declared as dependencies - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-parallel - value_type: bool - default_value: "true" - description: DEPRECATED disable parallel pulling. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: parallel - value_type: bool - default_value: "true" - description: DEPRECATED pull multiple images in parallel. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet - shorthand: q - value_type: bool - default_value: "false" - description: Pull without printing progress information - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: ignore-pull-failures + value_type: bool + default_value: "false" + description: Pull what it can and ignores images with pull failures + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: include-deps + value_type: bool + default_value: "false" + description: Also pull services declared as dependencies + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-parallel + value_type: bool + default_value: "true" + description: DEPRECATED disable parallel pulling. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: parallel + value_type: bool + default_value: "true" + description: DEPRECATED pull multiple images in parallel. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet + shorthand: q + value_type: bool + default_value: "false" + description: Pull without printing progress information + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false examples: |- - suppose you have this `compose.yaml`: + suppose you have this `compose.yaml`: - ```yaml - services: - db: - image: postgres - web: - build: . - command: bundle exec rails s -p 3000 -b '0.0.0.0' - volumes: - - .:/myapp - ports: - - "3000:3000" - depends_on: - - db - ``` + ```yaml + services: + db: + image: postgres + web: + build: . + command: bundle exec rails s -p 3000 -b '0.0.0.0' + volumes: + - .:/myapp + ports: + - "3000:3000" + depends_on: + - db + ``` - If you run `docker compose pull ServiceName` in the same directory as the `compose.yaml` file that defines the service, - Docker pulls the associated image. For example, to call the postgres image configured as the db service in our example, - you would run `docker compose pull db`. + If you run `docker compose pull ServiceName` in the same directory as the `compose.yaml` file that defines the service, + Docker pulls the associated image. For example, to call the postgres image configured as the db service in our example, + you would run `docker compose pull db`. - ```console - $ docker compose pull db - [+] Running 1/15 - ⠸ db Pulling 12.4s - ⠿ 45b42c59be33 Already exists 0.0s - ⠹ 40adec129f1a Downloading 3.374MB/4.178MB 9.3s - ⠹ b4c431d00c78 Download complete 9.3s - ⠹ 2696974e2815 Download complete 9.3s - ⠹ 564b77596399 Downloading 5.622MB/7.965MB 9.3s - ⠹ 5044045cf6f2 Downloading 216.7kB/391.1kB 9.3s - ⠹ d736e67e6ac3 Waiting 9.3s - ⠹ 390c1c9a5ae4 Waiting 9.3s - ⠹ c0e62f172284 Waiting 9.3s - ⠹ ebcdc659c5bf Waiting 9.3s - ⠹ 29be22cb3acc Waiting 9.3s - ⠹ f63c47038e66 Waiting 9.3s - ⠹ 77a0c198cde5 Waiting 9.3s - ⠹ c8752d5b785c Waiting 9.3s - ``̀` + ```console + $ docker compose pull db + [+] Running 1/15 + ⠸ db Pulling 12.4s + ⠿ 45b42c59be33 Already exists 0.0s + ⠹ 40adec129f1a Downloading 3.374MB/4.178MB 9.3s + ⠹ b4c431d00c78 Download complete 9.3s + ⠹ 2696974e2815 Download complete 9.3s + ⠹ 564b77596399 Downloading 5.622MB/7.965MB 9.3s + ⠹ 5044045cf6f2 Downloading 216.7kB/391.1kB 9.3s + ⠹ d736e67e6ac3 Waiting 9.3s + ⠹ 390c1c9a5ae4 Waiting 9.3s + ⠹ c0e62f172284 Waiting 9.3s + ⠹ ebcdc659c5bf Waiting 9.3s + ⠹ 29be22cb3acc Waiting 9.3s + ⠹ f63c47038e66 Waiting 9.3s + ⠹ 77a0c198cde5 Waiting 9.3s + ⠹ c8752d5b785c Waiting 9.3s + ``` deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_push.yaml b/docs/reference/docker_compose_push.yaml index f006ad61..d4dbb142 100644 --- a/docs/reference/docker_compose_push.yaml +++ b/docs/reference/docker_compose_push.yaml @@ -1,38 +1,38 @@ command: docker compose push short: Push service images long: |- - Pushes images for services to their respective registry/repository. + Pushes images for services to their respective registry/repository. - The following assumptions are made: - - You are pushing an image you have built locally - - You have access to the build key + The following assumptions are made: + - You are pushing an image you have built locally + - You have access to the build key - Examples + Examples - ```yaml - services: - service1: - build: . - image: localhost:5000/yourimage ## goes to local registry + ```yaml + services: + service1: + build: . + image: localhost:5000/yourimage ## goes to local registry - service2: - build: . - image: your-dockerid/yourimage ## goes to your repository on Docker Hub - ``` -usage: docker compose push [SERVICE...] + service2: + build: . + image: your-dockerid/yourimage ## goes to your repository on Docker Hub + ``` +usage: docker compose push [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: ignore-push-failures - value_type: bool - default_value: "false" - description: Push what it can and ignores images with push failures - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: ignore-push-failures + value_type: bool + default_value: "false" + description: Push what it can and ignores images with push failures + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_restart.yaml b/docs/reference/docker_compose_restart.yaml index 9f646cc0..ea6c2628 100644 --- a/docs/reference/docker_compose_restart.yaml +++ b/docs/reference/docker_compose_restart.yaml @@ -1,31 +1,31 @@ command: docker compose restart -short: Restart containers +short: Restart service containers long: |- - Restarts all stopped and running services. + Restarts all stopped and running services, or the specified services only. - If you make changes to your `compose.yml` configuration, these changes are not reflected - after running this command. For example, changes to environment variables (which are added - after a container is built, but before the container's command is executed) are not updated - after restarting. + If you make changes to your `compose.yml` configuration, these changes are not reflected + after running this command. For example, changes to environment variables (which are added + after a container is built, but before the container's command is executed) are not updated + after restarting. - 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 + 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 [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: timeout - shorthand: t - value_type: int - default_value: "10" - description: Specify a shutdown timeout in seconds - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: timeout + shorthand: t + value_type: int + default_value: "10" + description: Specify a shutdown timeout in seconds + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_rm.yaml b/docs/reference/docker_compose_rm.yaml index 48108dcd..4c5f748b 100644 --- a/docs/reference/docker_compose_rm.yaml +++ b/docs/reference/docker_compose_rm.yaml @@ -1,69 +1,69 @@ command: docker compose rm short: Removes stopped service containers long: |- - Removes stopped service containers. + Removes stopped service containers. - By default, anonymous volumes attached to containers are not removed. You can override this with `-v`. To list all - volumes, use `docker volume ls`. + By default, anonymous volumes attached to containers are not removed. You can override this with `-v`. To list all + volumes, use `docker volume ls`. - Any data which is not in a volume is lost. + Any data which is not in a volume is lost. - Running the command with no options also removes one-off containers created by `docker compose run`: + Running the command with no options also removes one-off containers created by `docker compose run`: - ```console - $ docker compose rm - Going to remove djangoquickstart_web_run_1 - Are you sure? [yN] y - Removing djangoquickstart_web_run_1 ... done - ``` -usage: docker compose rm [SERVICE...] + ```console + $ docker compose rm + Going to remove djangoquickstart_web_run_1 + Are you sure? [yN] y + Removing djangoquickstart_web_run_1 ... done + ``` +usage: docker compose rm [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: all - shorthand: a - value_type: bool - default_value: "false" - description: Deprecated - no effect - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: force - shorthand: f - value_type: bool - default_value: "false" - description: Don't ask to confirm removal - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: stop - shorthand: s - value_type: bool - default_value: "false" - description: Stop the containers, if required, before removing - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: volumes - shorthand: v - value_type: bool - default_value: "false" - description: Remove any anonymous volumes attached to containers - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: all + shorthand: a + value_type: bool + default_value: "false" + description: Deprecated - no effect + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: force + shorthand: f + value_type: bool + default_value: "false" + description: Don't ask to confirm removal + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: stop + shorthand: s + value_type: bool + default_value: "false" + description: Stop the containers, if required, before removing + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: volumes + shorthand: v + value_type: bool + default_value: "false" + description: Remove any anonymous volumes attached to containers + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_run.yaml b/docs/reference/docker_compose_run.yaml index 1862a70a..3783605b 100644 --- a/docs/reference/docker_compose_run.yaml +++ b/docs/reference/docker_compose_run.yaml @@ -1,242 +1,241 @@ command: docker compose run short: Run a one-off command on a service. long: |- - Runs a one-time command against a service. + Runs a one-time command against a service. - the following command starts the `web` service and runs `bash` as its command: + the following command starts the `web` service and runs `bash` as its command: - ```console - $ docker compose run web bash - ``` + ```console + $ docker compose run web bash + ``` - Commands you use with run start in new containers with configuration defined by that of the service, - including volumes, links, and other details. However, there are two important differences: + Commands you use with run start in new containers with configuration defined by that of the service, + including volumes, links, and other details. However, there are two important differences: - First, the command passed by `run` overrides the command defined in the service configuration. For example, if the - `web` service configuration is started with `bash`, then `docker compose run web python app.py` overrides it with - `python app.py`. + First, the command passed by `run` overrides the command defined in the service configuration. For example, if the + `web` service configuration is started with `bash`, then `docker compose run web python app.py` overrides it with + `python app.py`. - The second difference is that the `docker compose run` command does not create any of the ports specified in the - service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports - to be created and mapped to the host, specify the `--service-ports` + The second difference is that the `docker compose run` command does not create any of the ports specified in the + service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports + to be created and mapped to the host, specify the `--service-ports` - ```console - $ docker compose run --service-ports web python manage.py shell - ``` + ```console + $ docker compose run --service-ports web python manage.py shell + ``` - Alternatively, manual port mapping can be specified with the `--publish` or `-p` options, just as when using docker run: + Alternatively, manual port mapping can be specified with the `--publish` or `-p` options, just as when using docker run: - ```console - $ docker compose run --publish 8080:80 -p 2022:22 -p 127.0.0.1:2021:21 web python manage.py shell - ``` + ```console + $ docker compose run --publish 8080:80 -p 2022:22 -p 127.0.0.1:2021:21 web python manage.py shell + ``` - If you start a service configured with links, the run command first checks to see if the linked service is running - and starts the service if it is stopped. Once all the linked services are running, the run executes the command you - passed it. For example, you could run: + If you start a service configured with links, the run command first checks to see if the linked service is running + and starts the service if it is stopped. Once all the linked services are running, the run executes the command you + passed it. For example, you could run: - ```console - $ docker compose run db psql -h db -U docker - ``` + ```console + $ docker compose run db psql -h db -U docker + ``` - This opens an interactive PostgreSQL shell for the linked `db` container. + This opens an interactive PostgreSQL shell for the linked `db` container. - If you do not want the run command to start linked containers, use the `--no-deps` flag: + If you do not want the run command to start linked containers, use the `--no-deps` flag: - ```console - $ docker compose run --no-deps web python manage.py shell - ``` + ```console + $ docker compose run --no-deps web python manage.py shell + ``` - If you want to remove the container after running while overriding the container’s restart policy, use the `--rm` flag: + If you want to remove the container after running while overriding the container’s restart policy, use the `--rm` flag: - ```console - $ docker compose run --rm web python manage.py db upgrade - ``` + ```console + $ docker compose run --rm web python manage.py db upgrade + ``` - 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...] + 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] SERVICE [COMMAND] [ARGS...] pname: docker compose plink: docker_compose.yaml options: -- option: detach - shorthand: d - value_type: bool - default_value: "false" - description: Run container in background and print container ID - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: entrypoint - value_type: string - description: Override the entrypoint of the image - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: env - shorthand: e - value_type: stringArray - default_value: '[]' - description: Set environment variables - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: interactive - shorthand: i - value_type: bool - default_value: "true" - description: Keep STDIN open even if not attached. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: label - shorthand: l - value_type: stringArray - default_value: '[]' - description: Add or override a label - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: name - value_type: string - description: Assign a name to the container - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-TTY - shorthand: T - value_type: bool - default_value: "true" - description: 'Disable pseudo-TTY allocation (default: auto-detected).' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-deps - value_type: bool - default_value: "false" - description: Don't start linked services. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: publish - shorthand: p - value_type: stringArray - default_value: '[]' - description: Publish a container's port(s) to the host. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet-pull - value_type: bool - default_value: "false" - description: Pull without printing progress information. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: rm - value_type: bool - default_value: "false" - description: Automatically remove the container when it exits - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: service-ports - value_type: bool - default_value: "false" - description: | - Run command with the service's ports enabled and mapped to the host. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: tty - shorthand: t - value_type: bool - default_value: "true" - description: Allocate a pseudo-TTY. - deprecated: false - hidden: true - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: use-aliases - value_type: bool - default_value: "false" - description: | - Use the service's network useAliases in the network(s) the container connects to. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: user - shorthand: u - value_type: string - description: Run as specified username or uid - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: volume - shorthand: v - value_type: stringArray - default_value: '[]' - description: Bind mount a volume. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: workdir - shorthand: w - value_type: string - description: Working directory inside the container - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: detach + shorthand: d + value_type: bool + default_value: "false" + description: Run container in background and print container ID + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: entrypoint + value_type: string + description: Override the entrypoint of the image + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: env + shorthand: e + value_type: stringArray + default_value: '[]' + description: Set environment variables + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: interactive + shorthand: i + value_type: bool + default_value: "true" + description: Keep STDIN open even if not attached. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: label + shorthand: l + value_type: stringArray + default_value: '[]' + description: Add or override a label + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: name + value_type: string + description: Assign a name to the container + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-TTY + shorthand: T + value_type: bool + default_value: "true" + description: 'Disable pseudo-TTY allocation (default: auto-detected).' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-deps + value_type: bool + default_value: "false" + description: Don't start linked services. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: publish + shorthand: p + value_type: stringArray + default_value: '[]' + description: Publish a container's port(s) to the host. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet-pull + value_type: bool + default_value: "false" + description: Pull without printing progress information. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: rm + value_type: bool + default_value: "false" + description: Automatically remove the container when it exits + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: service-ports + value_type: bool + default_value: "false" + description: | + Run command with the service's ports enabled and mapped to the host. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: tty + shorthand: t + value_type: bool + default_value: "true" + description: Allocate a pseudo-TTY. + deprecated: false + hidden: true + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: use-aliases + value_type: bool + default_value: "false" + description: | + Use the service's network useAliases in the network(s) the container connects to. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: user + shorthand: u + value_type: string + description: Run as specified username or uid + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: volume + shorthand: v + value_type: stringArray + default_value: '[]' + description: Bind mount a volume. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: workdir + shorthand: w + value_type: string + description: Working directory inside the container + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_stop.yaml b/docs/reference/docker_compose_stop.yaml index e0c74f59..c79e41f3 100644 --- a/docs/reference/docker_compose_stop.yaml +++ b/docs/reference/docker_compose_stop.yaml @@ -1,22 +1,22 @@ 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...] + Stops running containers without removing them. They can be started again with `docker compose start`. +usage: docker compose stop [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: timeout - shorthand: t - value_type: int - default_value: "10" - description: Specify a shutdown timeout in seconds - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: timeout + shorthand: t + value_type: int + default_value: "10" + description: Specify a shutdown timeout in seconds + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_top.yaml b/docs/reference/docker_compose_top.yaml index 73987efc..1624feb9 100644 --- a/docs/reference/docker_compose_top.yaml +++ b/docs/reference/docker_compose_top.yaml @@ -5,12 +5,12 @@ usage: docker compose top [SERVICES...] pname: docker compose plink: docker_compose.yaml examples: |- - ```console - $ docker compose top - example_foo_1 - UID PID PPID C STIME TTY TIME CMD - root 142353 142331 2 15:33 ? 00:00:00 ping localhost -c 5 - ``` + ```console + $ docker compose top + example_foo_1 + UID PID PPID C STIME TTY TIME CMD + root 142353 142331 2 15:33 ? 00:00:00 ping localhost -c 5 + ``` deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_up.yaml b/docs/reference/docker_compose_up.yaml index e76c20e8..cbcc4c58 100644 --- a/docs/reference/docker_compose_up.yaml +++ b/docs/reference/docker_compose_up.yaml @@ -1,235 +1,245 @@ command: docker compose up short: Create and start containers long: |- - Builds, (re)creates, starts, and attaches to containers for a service. + Builds, (re)creates, starts, and attaches to containers for a service. - Unless they are already running, this command also starts any linked services. + Unless they are already running, this command also starts any linked services. - The `docker compose up` command aggregates the output of each container (like `docker compose logs --follow` does). - When the command exits, all containers are stopped. Running `docker compose up --detach` starts the containers in the - background and leaves them running. + The `docker compose up` command aggregates the output of each container (like `docker compose logs --follow` does). + When the command exits, all containers are stopped. Running `docker compose up --detach` starts the containers in the + background and leaves them running. - If there are existing containers for a service, and the service’s configuration or image was changed after the - container’s creation, `docker compose up` picks up the changes by stopping and recreating the containers - (preserving mounted volumes). To prevent Compose from picking up changes, use the `--no-recreate` flag. + If there are existing containers for a service, and the service’s configuration or image was changed after the + container’s creation, `docker compose up` picks up the changes by stopping and recreating the containers + (preserving mounted volumes). To prevent Compose from picking up changes, use the `--no-recreate` flag. - If you want to force Compose to stop and recreate all containers, use the `--force-recreate` flag. + If you want to force Compose to stop and recreate all containers, use the `--force-recreate` flag. - 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...] + 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 [OPTIONS] [SERVICE...] pname: docker compose plink: docker_compose.yaml options: -- option: abort-on-container-exit - value_type: bool - default_value: "false" - description: | - Stops all containers if any container was stopped. Incompatible with -d - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: always-recreate-deps - value_type: bool - default_value: "false" - description: Recreate dependent containers. Incompatible with --no-recreate. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: attach - value_type: stringArray - default_value: '[]' - description: Attach to service output. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: attach-dependencies - value_type: bool - default_value: "false" - description: Attach to dependent containers. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: build - value_type: bool - default_value: "false" - description: Build images before starting containers. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: detach - shorthand: d - value_type: bool - default_value: "false" - description: 'Detached mode: Run containers in the background' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: exit-code-from - value_type: string - description: | - Return the exit code of the selected service container. Implies --abort-on-container-exit - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: force-recreate - value_type: bool - default_value: "false" - description: | - Recreate containers even if their configuration and image haven't changed. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-build - value_type: bool - default_value: "false" - description: Don't build an image, even if it's missing. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-color - value_type: bool - default_value: "false" - description: Produce monochrome output. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-deps - value_type: bool - default_value: "false" - description: Don't start linked services. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-log-prefix - value_type: bool - default_value: "false" - description: Don't print prefix in logs. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-recreate - value_type: bool - default_value: "false" - description: | - If containers already exist, don't recreate them. Incompatible with --force-recreate. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: no-start - value_type: bool - default_value: "false" - description: Don't start the services after creating them. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: quiet-pull - value_type: bool - default_value: "false" - description: Pull without printing progress information. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- 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: renew-anon-volumes - shorthand: V - value_type: bool - default_value: "false" - description: | - Recreate anonymous volumes instead of retrieving data from the previous containers. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: scale - value_type: stringArray - default_value: '[]' - description: | - Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: timeout - shorthand: t - value_type: int - default_value: "10" - description: | - Use this timeout in seconds for container shutdown when attached or when containers are already running. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: wait - value_type: bool - default_value: "false" - description: Wait for services to be running|healthy. Implies detached mode. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: abort-on-container-exit + value_type: bool + default_value: "false" + description: | + Stops all containers if any container was stopped. Incompatible with -d + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: always-recreate-deps + value_type: bool + default_value: "false" + description: Recreate dependent containers. Incompatible with --no-recreate. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: attach + value_type: stringArray + default_value: '[]' + description: Attach to service output. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: attach-dependencies + value_type: bool + default_value: "false" + description: Attach to dependent containers. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: build + value_type: bool + default_value: "false" + description: Build images before starting containers. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: detach + shorthand: d + value_type: bool + default_value: "false" + description: 'Detached mode: Run containers in the background' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: exit-code-from + value_type: string + description: | + Return the exit code of the selected service container. Implies --abort-on-container-exit + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: force-recreate + value_type: bool + default_value: "false" + description: | + Recreate containers even if their configuration and image haven't changed. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-build + value_type: bool + default_value: "false" + description: Don't build an image, even if it's missing. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-color + value_type: bool + default_value: "false" + description: Produce monochrome output. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-deps + value_type: bool + default_value: "false" + description: Don't start linked services. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-log-prefix + value_type: bool + default_value: "false" + description: Don't print prefix in logs. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-recreate + value_type: bool + default_value: "false" + description: | + If containers already exist, don't recreate them. Incompatible with --force-recreate. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: no-start + value_type: bool + default_value: "false" + description: Don't start the services after creating them. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: pull + value_type: string + default_value: missing + description: Pull image before running ("always"|"missing"|"never") + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: quiet-pull + value_type: bool + default_value: "false" + description: Pull without printing progress information. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - 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: renew-anon-volumes + shorthand: V + value_type: bool + default_value: "false" + description: | + Recreate anonymous volumes instead of retrieving data from the previous containers. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: scale + value_type: stringArray + default_value: '[]' + description: | + Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: timeout + shorthand: t + value_type: int + default_value: "10" + description: | + Use this timeout in seconds for container shutdown when attached or when containers are already running. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: wait + value_type: bool + default_value: "false" + description: Wait for services to be running|healthy. Implies detached mode. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/docs/reference/docker_compose_version.yaml b/docs/reference/docker_compose_version.yaml index cc7c5ca3..3834264d 100644 --- a/docs/reference/docker_compose_version.yaml +++ b/docs/reference/docker_compose_version.yaml @@ -1,30 +1,30 @@ 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: -- option: format - shorthand: f - value_type: string - description: 'Format the output. Values: [pretty | json]. (Default: pretty)' - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false -- option: short - value_type: bool - default_value: "false" - description: Shows only Compose's version number. - deprecated: false - hidden: false - experimental: false - experimentalcli: false - kubernetes: false - swarm: false + - option: format + shorthand: f + value_type: string + description: 'Format the output. Values: [pretty | json]. (Default: pretty)' + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: short + value_type: bool + default_value: "false" + description: Shows only Compose's version number. + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false deprecated: false experimental: false experimentalcli: false diff --git a/go.mod b/go.mod index 5829b335..a6024a3d 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,14 @@ 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.4 - github.com/compose-spec/compose-go v1.2.8 + github.com/cnabio/cnab-to-oci v0.3.6 + github.com/compose-spec/compose-go v1.4.0 github.com/containerd/console v1.0.3 - github.com/containerd/containerd v1.6.6 - github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e + github.com/containerd/containerd v1.6.7 + 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.4.0 + github.com/docker/cli-docs-tool v0.5.0 github.com/docker/docker v20.10.17+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/go-units v0.4.0 @@ -21,19 +21,19 @@ require ( github.com/hashicorp/go-version v1.6.0 github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-shellwords v1.0.12 - github.com/moby/buildkit v0.10.1-0.20220403220257-10e6f94bf90d + github.com/moby/buildkit v0.10.3 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.8.1 + 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-20210220032951-036812b2e83c + 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 @@ -61,7 +61,7 @@ require ( github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.0 // indirect @@ -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-20220422013727-9388b58f7150 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // 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 diff --git a/go.sum b/go.sum index 5db359a7..7f04cbf4 100644 --- a/go.sum +++ b/go.sum @@ -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.4 h1:u1AUUplhKojCMgee17QkjU27yM1tfH9fOTFvxkrEqVw= -github.com/cnabio/cnab-to-oci v0.3.4/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.2.8 h1:ImPy82xn+rJKL5xmgEyesZEfqJmrzJ1WuZSHEhxMEFI= -github.com/compose-spec/compose-go v1.2.8/go.mod h1:813WrDd7NtOl9ZVqswlJ5iCQy3lxI3KYxKkY8EeHQ7w= +github.com/compose-spec/compose-go v1.4.0 h1:zaYVAZ6lIByr7Jffi20AabfeUwcTrdXfH3X1R5HEm+g= +github.com/compose-spec/compose-go v1.4.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.7 h1:IVikHEHEMZ5SXpUa80tNGNIV7fBigjp+sOcrlzAkPCc= +github.com/containerd/containerd v1.6.7/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= @@ -447,15 +448,17 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 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 h1:n81KvOMrLZa+VWHwST7dun9f0G98X3zREHS1ztYzZKU= github.com/distribution/distribution/v3 v3.0.0-20210316161203-a01c71e2477e/go.mod h1:xpWTC2KnJMiDLkoawhsPQcXjvwATEBcbq0xevG2YR9M= +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= github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible h1:RWXvuBczWuSIMjI69AnkNklNNVX2gmS0X+15AttGDVk= github.com/docker/cli v20.10.3-0.20220309205733-2b52f62e9627+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli-docs-tool v0.4.0 h1:MdfKoErGEbFqIxQ8an9BsZ+YzKUGd58RBVkV+Q82GPo= github.com/docker/cli-docs-tool v0.4.0/go.mod h1:rgW5KKdNpLMBIuH4WQ/1RNh38nH+/Ay5jgL4P0ZMPpY= +github.com/docker/cli-docs-tool v0.5.0 h1:EjGwI6EyB7YemHCC7R8mwXszJTbuq0T0pFuDC5bMhcE= +github.com/docker/cli-docs-tool v0.5.0/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -606,8 +609,8 @@ github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQq github.com/gofrs/flock v0.7.3/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= @@ -704,8 +707,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE= github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOtWDuPqjW0hJZt4rNdTZ4= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= @@ -1011,14 +1015,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.3 h1:/dGykD8FW+H4p++q5+KqKEo6gAkYKyBQHdawdjVwVAU= +github.com/moby/buildkit v0.10.3/go.mod h1:jxeOuly98l9gWHai0Ojrbnczrk/rf+o9/JqNhY+UCSo= 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= @@ -1218,8 +1222,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= @@ -1245,8 +1247,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= @@ -1673,8 +1676,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1790,8 +1794,9 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= 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/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= @@ -1909,7 +1914,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= diff --git a/pkg/api/api.go b/pkg/api/api.go index 08f6433d..9c3fc240 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -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 @@ -201,6 +205,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 +219,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 +280,7 @@ type ListOptions struct { // PsOptions group options of the Ps API type PsOptions struct { + Project *types.Project All bool Services []string } @@ -377,6 +386,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 ( @@ -445,3 +456,15 @@ const ( // UserCancel user cancelled compose up, we are stopping containers UserCancel ) + +// Separator is used for naming components +var Separator = "-" + +// GetImageNameOrDefault computes the default image name for a service, used to tag built images +func GetImageNameOrDefault(service types.ServiceConfig, projectName string) string { + imageName := service.Image + if imageName == "" { + imageName = projectName + Separator + service.Name + } + return imageName +} diff --git a/pkg/api/errors.go b/pkg/api/errors.go index 4cdcd800..e7820168 100644 --- a/pkg/api/errors.go +++ b/pkg/api/errors.go @@ -21,7 +21,7 @@ import ( ) const ( - //ExitCodeLoginRequired exit code when command cannot execute because it requires cloud login + // ExitCodeLoginRequired exit code when command cannot execute because it requires cloud login // This will be used by VSCode to detect when creating context if the user needs to login first ExitCodeLoginRequired = 5 ) diff --git a/pkg/compose/attach.go b/pkg/compose/attach.go index 42b815f3..52e90519 100644 --- a/pkg/compose/attach.go +++ b/pkg/compose/attach.go @@ -127,9 +127,9 @@ func (s *composeService) attachContainerStreams(ctx context.Context, container s if stdout != nil { go func() { if tty { - io.Copy(stdout, streamOut) // nolint:errcheck + io.Copy(stdout, streamOut) //nolint:errcheck } else { - stdcopy.StdCopy(stdout, stderr, streamOut) // nolint:errcheck + stdcopy.StdCopy(stdout, stderr, streamOut) //nolint:errcheck } }() } diff --git a/pkg/compose/build.go b/pkg/compose/build.go index 689a6cd8..995ada52 100644 --- a/pkg/compose/build.go +++ b/pkg/compose/build.go @@ -48,12 +48,9 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions) error { opts := map[string]build.Options{} - imagesToBuild := []string{} + 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 { @@ -61,29 +58,30 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti } for _, service := range services { - if service.Build != nil { - imageName := getImageName(service, project.Name) - imagesToBuild = append(imagesToBuild, imageName) - buildOptions, err := s.toBuildOptions(project, service, imageName, options.SSHs) - if err != nil { - return err - } - buildOptions.Pull = options.Pull - buildOptions.BuildArgs = mergeArgs(buildOptions.BuildArgs, args) - buildOptions.NoCache = options.NoCache - buildOptions.CacheFrom, err = buildflags.ParseCacheEntry(service.Build.CacheFrom) - if err != nil { - return err - } - - for _, image := range service.Build.CacheFrom { - buildOptions.CacheFrom = append(buildOptions.CacheFrom, bclient.CacheOptionsEntry{ - Type: "registry", - Attrs: map[string]string{"ref": image}, - }) - } - opts[imageName] = buildOptions + if service.Build == nil { + continue } + imageName := api.GetImageNameOrDefault(service, project.Name) + imagesToBuild = append(imagesToBuild, imageName) + buildOptions, err := s.toBuildOptions(project, service, imageName, options.SSHs) + if err != nil { + return err + } + buildOptions.Pull = options.Pull + buildOptions.BuildArgs = mergeArgs(buildOptions.BuildArgs, args) + buildOptions.NoCache = options.NoCache + buildOptions.CacheFrom, err = buildflags.ParseCacheEntry(service.Build.CacheFrom) + if err != nil { + return err + } + + for _, image := range service.Build.CacheFrom { + buildOptions.CacheFrom = append(buildOptions.CacheFrom, bclient.CacheOptionsEntry{ + Type: "registry", + Attrs: map[string]string{"ref": image}, + }) + } + opts[imageName] = buildOptions } _, err = s.doBuild(ctx, project, opts, options.Progress) @@ -134,14 +132,13 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types. } // set digest as com.docker.compose.image label so we can detect outdated containers for i, service := range project.Services { - image := getImageName(service, project.Name) + image := api.GetImageNameOrDefault(service, project.Name) digest, ok := images[image] if ok { if project.Services[i].Labels == nil { project.Services[i].Labels = types.Labels{} } project.Services[i].CustomLabels[api.ImageDigestLabel] = digest - project.Services[i].Image = image } } return nil @@ -153,7 +150,7 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri if service.Image == "" && service.Build == nil { return nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name) } - imageName := getImageName(service, project.Name) + imageName := api.GetImageNameOrDefault(service, project.Name) _, localImagePresent := images[imageName] if service.Build != nil { @@ -173,9 +170,9 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri } func (s *composeService) getLocalImagesDigests(ctx context.Context, project *types.Project) (map[string]string, error) { - imageNames := []string{} + var imageNames []string for _, s := range project.Services { - imgName := getImageName(s, project.Name) + imgName := api.GetImageNameOrDefault(s, project.Name) if !utils.StringContains(imageNames, imgName) { imageNames = append(imageNames, imgName) } @@ -189,11 +186,11 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ images[name] = info.ID } - for _, s := range project.Services { - imgName := getImageName(s, project.Name) + for i := range project.Services { + imgName := api.GetImageNameOrDefault(project.Services[i], project.Name) digest, ok := images[imgName] if ok { - s.CustomLabels[api.ImageDigestLabel] = digest + project.Services[i].CustomLabels.Add(api.ImageDigestLabel, digest) } } @@ -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 { @@ -256,23 +250,11 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se } if len(service.Build.Secrets) > 0 { - var sources []secretsprovider.Source - for _, secret := range service.Build.Secrets { - config := project.Secrets[secret.Source] - if config.File == "" { - return build.Options{}, fmt.Errorf("build.secrets only supports file-based secrets: %q", secret.Source) - } - sources = append(sources, secretsprovider.Source{ - ID: secret.Source, - FilePath: config.File, - }) - } - store, err := secretsprovider.NewStore(sources) + secretsProvider, err := addSecretsConfig(project, service) if err != nil { return build.Options{}, err } - p := secretsprovider.NewSecretProvider(store) - sessionConfig = append(sessionConfig, p) + sessionConfig = append(sessionConfig, secretsProvider) } if len(service.Build.Tags) > 0 { @@ -324,11 +306,11 @@ func mergeArgs(m ...types.Mapping) types.Mapping { return merged } -func dockerFilePath(context string, dockerfile string) string { - if urlutil.IsGitURL(context) || filepath.IsAbs(dockerfile) { +func dockerFilePath(ctxName string, dockerfile string) string { + if urlutil.IsGitURL(ctxName) || filepath.IsAbs(dockerfile) { return dockerfile } - return filepath.Join(context, dockerfile) + return filepath.Join(ctxName, dockerfile) } func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) { @@ -341,3 +323,30 @@ func sshAgentProvider(sshKeys types.SSHConfig) (session.Attachable, error) { } return sshprovider.NewSSHAgentProvider(sshConfig) } + +func addSecretsConfig(project *types.Project, service types.ServiceConfig) (session.Attachable, error) { + + var sources []secretsprovider.Source + for _, secret := range service.Build.Secrets { + config := project.Secrets[secret.Source] + switch { + case config.File != "": + sources = append(sources, secretsprovider.Source{ + ID: secret.Source, + FilePath: config.File, + }) + case config.Environment != "": + sources = append(sources, secretsprovider.Source{ + ID: secret.Source, + Env: config.Environment, + }) + default: + return nil, fmt.Errorf("build.secrets only supports environment or file-based secrets: %q", secret.Source) + } + } + store, err := secretsprovider.NewStore(sources) + if err != nil { + return nil, err + } + return secretsprovider.NewSecretProvider(store), nil +} diff --git a/pkg/compose/build_classic.go b/pkg/compose/build_classic.go index 3c6487be..dc88dee3 100644 --- a/pkg/compose/build_classic.go +++ b/pkg/compose/build_classic.go @@ -29,6 +29,7 @@ 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" @@ -45,7 +46,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj var nameDigests = make(map[string]string) var errs error err := project.WithServices(nil, func(service types.ServiceConfig) error { - imageName := getImageName(service, project.Name) + imageName := api.GetImageNameOrDefault(service, project.Name) o, ok := opts[imageName] if !ok { return nil @@ -64,7 +65,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 @@ -96,7 +97,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options if err != nil { return "", errors.Errorf("unable to open Dockerfile: %v", err) } - defer dockerfileCtx.Close() // nolint:errcheck + defer dockerfileCtx.Close() //nolint:errcheck } case urlutil.IsGitURL(specifiedContext): tempDir, relDockerfile, err = build.GetContextFromGitURL(specifiedContext, dockerfileName) @@ -111,7 +112,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options } if tempDir != "" { - defer os.RemoveAll(tempDir) // nolint:errcheck + defer os.RemoveAll(tempDir) //nolint:errcheck contextDir = tempDir } @@ -175,7 +176,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options if err != nil { return "", err } - defer response.Body.Close() // nolint:errcheck + defer response.Body.Close() //nolint:errcheck imageID := "" aux := func(msg jsonmessage.JSONMessage) { @@ -214,7 +215,7 @@ func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options if imageID == "" { return "", errors.Errorf("Server did not provide an image ID. Cannot write %s", options.ImageIDFile) } - if err := os.WriteFile(options.ImageIDFile, []byte(imageID), 0666); err != nil { + if err := os.WriteFile(options.ImageIDFile, []byte(imageID), 0o666); err != nil { return "", err } } diff --git a/pkg/compose/compose.go b/pkg/compose/compose.go index 5f7446e0..de8a3ecc 100644 --- a/pkg/compose/compose.go +++ b/pkg/compose/compose.go @@ -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,12 +35,8 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/pkg/errors" - "github.com/sanathkr/go-yaml" ) -// Separator is used for naming components -var Separator = "-" - // NewComposeService create a local implementation of the compose.Service API func NewComposeService(dockerCli command.Cli) api.Service { return &composeService{ @@ -175,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 { diff --git a/pkg/compose/convergence.go b/pkg/compose/convergence.go index 1db3bc3d..a2e43481 100644 --- a/pkg/compose/convergence.go +++ b/pkg/compose/convergence.go @@ -261,7 +261,7 @@ func mustRecreate(expected types.ServiceConfig, actual moby.Container, policy st } func getContainerName(projectName string, service types.ServiceConfig, number int) string { - name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, Separator) + name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, api.Separator) if service.ContainerName != "" { name = service.ContainerName } @@ -553,8 +553,8 @@ func (s composeService) getLinks(ctx context.Context, projectName string, servic containerName := getCanonicalContainerName(c) links = append(links, format(containerName, linkName), - format(containerName, strings.Join([]string{linkServiceName, strconv.Itoa(number)}, Separator)), - format(containerName, strings.Join([]string{projectName, linkServiceName, strconv.Itoa(number)}, Separator)), + format(containerName, linkServiceName+api.Separator+strconv.Itoa(number)), + format(containerName, strings.Join([]string{projectName, linkServiceName, strconv.Itoa(number)}, api.Separator)), ) } } @@ -568,7 +568,7 @@ func (s composeService) getLinks(ctx context.Context, projectName string, servic containerName := getCanonicalContainerName(c) links = append(links, format(containerName, service.Name), - format(containerName, strings.TrimPrefix(containerName, projectName+Separator)), + format(containerName, strings.TrimPrefix(containerName, projectName+api.Separator)), format(containerName, containerName), ) } @@ -605,8 +605,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{ diff --git a/pkg/compose/cp.go b/pkg/compose/cp.go index 558de13e..d7fcd89e 100644 --- a/pkg/compose/cp.go +++ b/pkg/compose/cp.go @@ -263,7 +263,7 @@ func (s *composeService) copyFromContainer(ctx context.Context, containerID, src } preArchive := content - if len(srcInfo.RebaseName) != 0 { + if srcInfo.RebaseName != "" { _, srcBase := archive.SplitPathDirEntry(srcInfo.Path) preArchive = archive.RebaseArchiveEntries(content, srcBase, srcInfo.RebaseName) } diff --git a/pkg/compose/create.go b/pkg/compose/create.go index 34e728eb..3ee694b0 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -227,14 +227,6 @@ func (s *composeService) ensureProjectVolumes(ctx context.Context, project *type return nil } -func getImageName(service types.ServiceConfig, projectName string) string { - imageName := service.Image - if imageName == "" { - imageName = projectName + "_" + service.Name - } - return imageName -} - func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, service types.ServiceConfig, number int, inherit *moby.Container, autoRemove bool, attachStdin bool) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) { @@ -279,7 +271,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project, AttachStderr: true, AttachStdout: true, Cmd: runCmd, - Image: getImageName(service, p.Name), + Image: api.GetImageNameOrDefault(service, p.Name), WorkingDir: service.WorkingDir, Entrypoint: entrypoint, NetworkDisabled: service.NetworkMode == "disabled", @@ -314,8 +306,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{ @@ -680,7 +673,7 @@ func getVolumesFrom(project *types.Project, volumesFrom []string) ([]string, []s continue } if spec[0] == "container" { - volumes = append(volumes, strings.Join(spec[1:], ":")) + volumes = append(volumes, vol) continue } serviceName := spec[0] @@ -712,7 +705,7 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj inherit *moby.Container) (map[string]struct{}, []string, []mount.Mount, error) { var mounts = []mount.Mount{} - image := getImageName(service, p.Name) + image := api.GetImageNameOrDefault(service, p.Name) imgInspect, _, err := s.apiClient().ImageInspectWithRaw(ctx, image) if err != nil { return nil, nil, nil, err @@ -727,8 +720,12 @@ func (s *composeService) buildContainerVolumes(ctx context.Context, p types.Proj binds := []string{} MOUNTS: for _, m := range mountOptions { + if m.Type == mount.TypeNamedPipe { + mounts = append(mounts, m) + continue + } volumeMounts[m.Target] = struct{}{} - if m.Type == mount.TypeBind || m.Type == mount.TypeNamedPipe { + if m.Type == mount.TypeBind { // `Mount` is preferred but does not offer option to created host path if missing // so `Bind` API is used here with raw volume string // see https://github.com/moby/moby/issues/43483 @@ -893,7 +890,7 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount continue } - mount, err := buildMount(p, types.ServiceVolumeConfig{ + mnt, err := buildMount(p, types.ServiceVolumeConfig{ Type: types.VolumeTypeBind, Source: definedSecret.File, Target: target, @@ -902,7 +899,7 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount if err != nil { return nil, err } - mounts[target] = mount + mounts[target] = mnt } values := make([]mount.Mount, 0, len(mounts)) for _, v := range mounts { @@ -911,8 +908,8 @@ func buildContainerSecretMounts(p types.Project, s types.ServiceConfig) ([]mount return values, nil } -func isUnixAbs(path string) bool { - return strings.HasPrefix(path, "/") +func isUnixAbs(p string) bool { + return strings.HasPrefix(p, "/") } func buildMount(project types.Project, volume types.ServiceVolumeConfig) (mount.Mount, error) { @@ -1041,7 +1038,14 @@ func (s *composeService) ensureNetwork(ctx context.Context, n types.NetworkConfi if err != nil { return err } - if len(networks) == 0 { + networkNotFound := true + for _, net := range networks { + if net.Name == n.Name { + networkNotFound = false + break + } + } + if networkNotFound { if n.External.External { if n.Driver == "overlay" { // Swarm nodes do not register overlay networks that were diff --git a/pkg/compose/create_test.go b/pkg/compose/create_test.go index 6c6a4f19..4b614046 100644 --- a/pkg/compose/create_test.go +++ b/pkg/compose/create_test.go @@ -22,11 +22,12 @@ import ( "sort" "testing" - "github.com/compose-spec/compose-go/types" - composetypes "github.com/compose-spec/compose-go/types" "github.com/docker/compose/v2/pkg/api" + + composetypes "github.com/compose-spec/compose-go/types" moby "github.com/docker/docker/api/types" mountTypes "github.com/docker/docker/api/types/mount" + "gotest.tools/v3/assert" ) @@ -45,6 +46,18 @@ func TestBuildBindMount(t *testing.T) { assert.Equal(t, mount.Type, mountTypes.TypeBind) } +func TestBuildNamedPipeMount(t *testing.T) { + project := composetypes.Project{} + volume := composetypes.ServiceVolumeConfig{ + Type: composetypes.VolumeTypeNamedPipe, + Source: "\\\\.\\pipe\\docker_engine_windows", + Target: "\\\\.\\pipe\\docker_engine", + } + mount, err := buildMount(project, volume) + assert.NilError(t, err) + assert.Equal(t, mount.Type, mountTypes.TypeNamedPipe) +} + func TestBuildVolumeMount(t *testing.T) { project := composetypes.Project{ Name: "myProject", @@ -66,17 +79,17 @@ func TestBuildVolumeMount(t *testing.T) { } func TestServiceImageName(t *testing.T) { - assert.Equal(t, getImageName(types.ServiceConfig{Image: "myImage"}, "myProject"), "myImage") - assert.Equal(t, getImageName(types.ServiceConfig{Name: "aService"}, "myProject"), "myProject_aService") + assert.Equal(t, api.GetImageNameOrDefault(composetypes.ServiceConfig{Image: "myImage"}, "myProject"), "myImage") + assert.Equal(t, api.GetImageNameOrDefault(composetypes.ServiceConfig{Name: "aService"}, "myProject"), "myProject-aService") } func TestPrepareNetworkLabels(t *testing.T) { - project := types.Project{ + project := composetypes.Project{ Name: "myProject", - Networks: types.Networks(map[string]types.NetworkConfig{"skynet": {}}), + Networks: composetypes.Networks(map[string]composetypes.NetworkConfig{"skynet": {}}), } prepareNetworks(&project) - assert.DeepEqual(t, project.Networks["skynet"].Labels, types.Labels(map[string]string{ + assert.DeepEqual(t, project.Networks["skynet"].Labels, composetypes.Labels(map[string]string{ "com.docker.compose.network": "skynet", "com.docker.compose.project": "myProject", "com.docker.compose.version": api.ComposeVersion, @@ -98,6 +111,11 @@ func TestBuildContainerMountOptions(t *testing.T) { Type: composetypes.VolumeTypeVolume, Target: "/var/myvolume2", }, + { + Type: composetypes.VolumeTypeNamedPipe, + Source: "\\\\.\\pipe\\docker_engine_windows", + Target: "\\\\.\\pipe\\docker_engine", + }, }, }, }, @@ -129,18 +147,20 @@ func TestBuildContainerMountOptions(t *testing.T) { return mounts[i].Target < mounts[j].Target }) assert.NilError(t, err) - assert.Assert(t, len(mounts) == 2) + assert.Assert(t, len(mounts) == 3) assert.Equal(t, mounts[0].Target, "/var/myvolume1") assert.Equal(t, mounts[1].Target, "/var/myvolume2") + assert.Equal(t, mounts[2].Target, "\\\\.\\pipe\\docker_engine") mounts, err = buildContainerMountOptions(project, project.Services[0], moby.ImageInspect{}, inherit) sort.Slice(mounts, func(i, j int) bool { return mounts[i].Target < mounts[j].Target }) assert.NilError(t, err) - assert.Assert(t, len(mounts) == 2) + assert.Assert(t, len(mounts) == 3) assert.Equal(t, mounts[0].Target, "/var/myvolume1") assert.Equal(t, mounts[1].Target, "/var/myvolume2") + assert.Equal(t, mounts[2].Target, "\\\\.\\pipe\\docker_engine") } func TestGetDefaultNetworkMode(t *testing.T) { diff --git a/pkg/compose/down.go b/pkg/compose/down.go index b04ac108..cd5af07b 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -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 } @@ -163,14 +166,16 @@ func (s *composeService) removeNetwork(ctx context.Context, name string, w progr var removed int for _, net := range networks { - if err := s.apiClient().NetworkRemove(ctx, net.ID); err != nil { - if errdefs.IsNotFound(err) { - continue + if net.Name == name { + if err := s.apiClient().NetworkRemove(ctx, net.ID); err != nil { + if errdefs.IsNotFound(err) { + continue + } + w.Event(progress.ErrorEvent(eventName)) + return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name)) } - w.Event(progress.ErrorEvent(eventName)) - return errors.Wrapf(err, fmt.Sprintf("failed to remove network %s", name)) + removed++ } - removed++ } if removed == 0 { @@ -193,7 +198,7 @@ func (s *composeService) getServiceImages(options api.DownOptions, project *type continue } if image == "" { - image = getImageName(service, project.Name) + image = api.GetImageNameOrDefault(service, project.Name) } images[image] = struct{}{} } diff --git a/pkg/compose/down_test.go b/pkg/compose/down_test.go index ea952793..0111fdea 100644 --- a/pkg/compose/down_test.go +++ b/pkg/compose/down_test.go @@ -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{ diff --git a/pkg/compose/envresolver.go b/pkg/compose/envresolver.go new file mode 100644 index 00000000..0d12c3dc --- /dev/null +++ b/pkg/compose/envresolver.go @@ -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 + } +} diff --git a/pkg/compose/envresolver_test.go b/pkg/compose/envresolver_test.go new file mode 100644 index 00000000..791bd5fb --- /dev/null +++ b/pkg/compose/envresolver_test.go @@ -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) + }) + } +} diff --git a/pkg/compose/hash.go b/pkg/compose/hash.go index e3f2aa0e..1e1abafa 100644 --- a/pkg/compose/hash.go +++ b/pkg/compose/hash.go @@ -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 diff --git a/pkg/compose/kill_test.go b/pkg/compose/kill_test.go index 9680afe3..1455b6c2 100644 --- a/pkg/compose/kill_test.go +++ b/pkg/compose/kill_test.go @@ -18,6 +18,7 @@ package compose import ( "context" + "fmt" "path/filepath" "strings" "testing" @@ -110,9 +111,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, } } diff --git a/pkg/compose/logs.go b/pkg/compose/logs.go index 7f252074..7d26c815 100644 --- a/pkg/compose/logs.go +++ b/pkg/compose/logs.go @@ -95,7 +95,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) { diff --git a/pkg/compose/ls.go b/pkg/compose/ls.go index 942827ef..f7094a32 100644 --- a/pkg/compose/ls.go +++ b/pkg/compose/ls.go @@ -106,9 +106,9 @@ func combinedStatus(statuses []string) string { for _, status := range keys { nb := nbByStatus[status] if result != "" { - result = result + ", " + result += ", " } - result = result + fmt.Sprintf("%s(%d)", status, nb) + result += fmt.Sprintf("%s(%d)", status, nb) } return result } diff --git a/pkg/compose/metrics.go b/pkg/compose/metrics.go index 2cdc927e..7bd9ad69 100644 --- a/pkg/compose/metrics.go +++ b/pkg/compose/metrics.go @@ -50,13 +50,13 @@ var ( ComposeParseFailure = FailureCategory{MetricsStatus: ComposeParseFailureStatus, ExitCode: 15} // CommandSyntaxFailure failure for command line syntax CommandSyntaxFailure = FailureCategory{MetricsStatus: CommandSyntaxFailureStatus, ExitCode: 16} - //BuildFailure failure while building images. + // BuildFailure failure while building images. BuildFailure = FailureCategory{MetricsStatus: BuildFailureStatus, ExitCode: 17} // PullFailure failure while pulling image PullFailure = FailureCategory{MetricsStatus: PullFailureStatus, ExitCode: 18} ) -//ByExitCode retrieve FailureCategory based on command exit code +// ByExitCode retrieve FailureCategory based on command exit code func ByExitCode(exitCode int) FailureCategory { switch exitCode { case 0: diff --git a/pkg/compose/pause.go b/pkg/compose/pause.go index 3ea593ee..02434b4f 100644 --- a/pkg/compose/pause.go +++ b/pkg/compose/pause.go @@ -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) { diff --git a/pkg/compose/printer.go b/pkg/compose/printer.go index 7942c564..cb150775 100644 --- a/pkg/compose/printer.go +++ b/pkg/compose/printer.go @@ -32,6 +32,11 @@ type logPrinter interface { Cancel() } +type printer struct { + queue chan api.ContainerEvent + consumer api.LogConsumer +} + // newLogPrinter builds a LogPrinter passing containers logs to LogConsumer func newLogPrinter(consumer api.LogConsumer) logPrinter { queue := make(chan api.ContainerEvent) @@ -48,11 +53,6 @@ func (p *printer) Cancel() { } } -type printer struct { - queue chan api.ContainerEvent - consumer api.LogConsumer -} - func (p *printer) HandleEvent(event api.ContainerEvent) { p.queue <- event } diff --git a/pkg/compose/ps.go b/pkg/compose/ps.go index de4b25f2..7df826a0 100644 --- a/pkg/compose/ps.go +++ b/pkg/compose/ps.go @@ -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 { diff --git a/pkg/compose/ps_test.go b/pkg/compose/ps_test.go index 2f17616e..669b09e2 100644 --- a/pkg/compose/ps_test.go +++ b/pkg/compose/ps_test.go @@ -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) diff --git a/pkg/compose/remove.go b/pkg/compose/remove.go index cc10b71a..557572b6 100644 --- a/pkg/compose/remove.go +++ b/pkg/compose/remove.go @@ -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 }) diff --git a/pkg/compose/restart.go b/pkg/compose/restart.go index 87d236cc..9b3178e3 100644 --- a/pkg/compose/restart.go +++ b/pkg/compose/restart.go @@ -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 } diff --git a/pkg/compose/run.go b/pkg/compose/run.go index 7b1295ab..2557e037 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -114,15 +114,12 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts service.Entrypoint = opts.Entrypoint } if len(opts.Environment) > 0 { - env := types.NewMappingWithEquals(opts.Environment) - projectEnv := env.Resolve(func(s string) (string, bool) { - if _, ok := service.Environment[s]; ok { - return "", false - } - v, ok := project.Environment[s] + cmdEnv := types.NewMappingWithEquals(opts.Environment) + serviceOverrideEnv := cmdEnv.Resolve(func(s string) (string, bool) { + v, ok := envResolver(project.Environment)(s) return v, ok }).RemoveEmpty() - service.Environment.OverrideBy(projectEnv) + service.Environment.OverrideBy(serviceOverrideEnv) } for k, v := range opts.Labels { service.Labels = service.Labels.Add(k, v) diff --git a/pkg/compose/secrets.go b/pkg/compose/secrets.go index a7114cbb..30815c3f 100644 --- a/pkg/compose/secrets.go +++ b/pkg/compose/secrets.go @@ -57,7 +57,7 @@ func createTar(env string, config types.ServiceSecretConfig) (bytes.Buffer, erro value := []byte(env) b := bytes.Buffer{} tarWriter := tar.NewWriter(&b) - mode := uint32(0400) + mode := uint32(0o400) if config.Mode != nil { mode = *config.Mode } diff --git a/pkg/compose/stop.go b/pkg/compose/stop.go index d17e01a9..971b7e99 100644 --- a/pkg/compose/stop.go +++ b/pkg/compose/stop.go @@ -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) }) } diff --git a/pkg/compose/stop_test.go b/pkg/compose/stop_test.go index e5848780..97a83356 100644 --- a/pkg/compose/stop_test.go +++ b/pkg/compose/stop_test.go @@ -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) diff --git a/pkg/compose/up.go b/pkg/compose/up.go index a20591b1..20acfa48 100644 --- a/pkg/compose/up.go +++ b/pkg/compose/up.go @@ -60,13 +60,13 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options return progress.Run(ctx, func(ctx context.Context) error { go func() { <-signalChan - s.Kill(ctx, project.Name, api.KillOptions{ // nolint:errcheck - Services: project.ServiceNames(), + s.Kill(ctx, project.Name, api.KillOptions{ //nolint:errcheck + Services: options.Create.Services, }) }() return s.Stop(ctx, project.Name, api.StopOptions{ - Services: project.ServiceNames(), + Services: options.Create.Services, }) }) } @@ -74,7 +74,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options <-signalChan printer.Cancel() fmt.Println("Gracefully stopping... (press Ctrl+C again to force)") - stopFunc() // nolint:errcheck + stopFunc() //nolint:errcheck }() var exitCode int diff --git a/pkg/e2e/assert.go b/pkg/e2e/assert.go new file mode 100644 index 00000000..5cfcc1d5 --- /dev/null +++ b/pkg/e2e/assert.go @@ -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"], + ) + } +} diff --git a/pkg/e2e/buffer.go b/pkg/e2e/buffer.go new file mode 100644 index 00000000..787e6c35 --- /dev/null +++ b/pkg/e2e/buffer.go @@ -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) +} diff --git a/pkg/e2e/build_test.go b/pkg/e2e/build_test.go index c7ea531b..178ed7f9 100644 --- a/pkg/e2e/build_test.go +++ b/pkg/e2e/build_test.go @@ -31,30 +31,30 @@ func TestLocalComposeBuild(t *testing.T) { t.Run("build named and unnamed images", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "build-test-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build") res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + c.RunDockerCmd(t, "image", "inspect", "build-test-nginx") c.RunDockerCmd(t, "image", "inspect", "custom-nginx") }) t.Run("build with build-arg", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "build-test-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "build", "--build-arg", "FOO=BAR") - res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + res := c.RunDockerCmd(t, "image", "inspect", "build-test-nginx") res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) }) t.Run("build with build-arg set by env", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "build-test-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx") icmd.RunCmd(c.NewDockerComposeCmd(t, @@ -67,20 +67,20 @@ func TestLocalComposeBuild(t *testing.T) { cmd.Env = append(cmd.Env, "FOO=BAR") }) - res := c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + res := c.RunDockerCmd(t, "image", "inspect", "build-test-nginx") res.Assert(t, icmd.Expected{Out: `"FOO": "BAR"`}) }) t.Run("build with multiple build-args ", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError(t, "rmi", "-f", "multi-args_multiargs") + c.RunDockerOrExitError(t, "rmi", "-f", "multi-args-multiargs") cmd := c.NewDockerComposeCmd(t, "--project-directory", "fixtures/build-test/multi-args", "build") icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { cmd.Env = append(cmd.Env, "DOCKER_BUILDKIT=0") }) - res := c.RunDockerCmd(t, "image", "inspect", "multi-args_multiargs") + res := c.RunDockerCmd(t, "image", "inspect", "multi-args-multiargs") res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`}) }) @@ -131,7 +131,7 @@ func TestLocalComposeBuild(t *testing.T) { }) t.Run("build as part of up", func(t *testing.T) { - c.RunDockerOrExitError(t, "rmi", "build-test_nginx") + c.RunDockerOrExitError(t, "rmi", "build-test-nginx") c.RunDockerOrExitError(t, "rmi", "custom-nginx") res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") @@ -145,7 +145,7 @@ func TestLocalComposeBuild(t *testing.T) { output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second) assert.Assert(t, strings.Contains(output, "Hello from Nginx container")) - c.RunDockerCmd(t, "image", "inspect", "build-test_nginx") + c.RunDockerCmd(t, "image", "inspect", "build-test-nginx") c.RunDockerCmd(t, "image", "inspect", "custom-nginx") }) @@ -164,7 +164,7 @@ func TestLocalComposeBuild(t *testing.T) { t.Run("cleanup build project", func(t *testing.T) { c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down") - c.RunDockerCmd(t, "rmi", "build-test_nginx") + c.RunDockerCmd(t, "rmi", "build-test-nginx") c.RunDockerCmd(t, "rmi", "custom-nginx") }) } @@ -176,7 +176,12 @@ func TestBuildSecrets(t *testing.T) { // ensure local test run does not reuse previously build image c.RunDockerOrExitError(t, "rmi", "build-test-secret") - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test/secrets", "build") + cmd := c.NewDockerComposeCmd(t, "--project-directory", "fixtures/build-test/secrets", "build") + + res := icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "SOME_SECRET=bar") + }) + res.Assert(t, icmd.Success) }) } @@ -211,10 +216,10 @@ func TestBuildImageDependencies(t *testing.T) { t.Cleanup(resetState) // the image should NOT exist now - res := cli.RunDockerOrExitError(t, "image", "inspect", "build-dependencies_service") + res := cli.RunDockerOrExitError(t, "image", "inspect", "build-dependencies-service") res.Assert(t, icmd.Expected{ ExitCode: 1, - Err: "Error: No such image: build-dependencies_service", + Err: "Error: No such image: build-dependencies-service", }) res = cli.RunDockerComposeCmd(t, "build") @@ -222,8 +227,8 @@ func TestBuildImageDependencies(t *testing.T) { res = cli.RunDockerCmd(t, "image", "inspect", "--format={{ index .RepoTags 0 }}", - "build-dependencies_service") - res.Assert(t, icmd.Expected{Out: "build-dependencies_service:latest"}) + "build-dependencies-service") + res.Assert(t, icmd.Expected{Out: "build-dependencies-service:latest"}) } t.Run("ClassicBuilder", func(t *testing.T) { diff --git a/pkg/e2e/compose_environment_test.go b/pkg/e2e/compose_environment_test.go index 3314617c..c57b5807 100644 --- a/pkg/e2e/compose_environment_test.go +++ b/pkg/e2e/compose_environment_test.go @@ -27,137 +27,196 @@ import ( func TestEnvPriority(t *testing.T) { c := NewParallelCLI(t) - projectDir := "./fixtures/environment/env-priority" - t.Run("up", func(t *testing.T) { c.RunDockerOrExitError(t, "rmi", "env-compose-priority") c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml", - "--project-directory", projectDir, "up", "-d", "--build") + "up", "-d", "--build") }) // Full options activated - // 1. Compose file <-- Result expected - // 2. Shell environment variables - // 3. Environment file - // 4. Dockerfile + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment patched by --env-file) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive // 5. Variable is not defined t.Run("compose file priority", func(t *testing.T) { cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml", - "--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", - "--rm", "-e", "WHEREAMI", "env-compose-priority") + "--env-file", "./fixtures/environment/env-priority/.env.override", + "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()), "Compose File") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "override") + }) + + // Full options activated + // 1. Command Line (docker compose run --env ) <-- Result expected + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("compose file priority", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override", + "run", "--rm", "-e", "WHEREAMI=shell", "env-compose-priority") + res := icmd.RunCmd(cmd) + assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell") }) // No Compose file, all other options - // 1. Compose file - // 2. Shell environment variables <-- Result expected - // 3. Environment file - // 4. Dockerfile + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment patched by --env-file) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive // 5. Variable is not defined t.Run("shell priority", func(t *testing.T) { - cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", - projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", - "WHEREAMI", "env-compose-priority") + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override", + "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") + }) + + // No Compose file, all other options with env variable from OS environment + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("shell priority file with default value", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override.with.default", + "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()), "shell") }) - // No Compose file and env variable pass to the run command - // 1. Compose file - // 2. Shell environment variables <-- Result expected - // 3. Environment file - // 4. Dockerfile + // No Compose file, all other options with env variable from OS environment + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment default value from file in --env-file) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("shell priority implicitly set", func(t *testing.T) { + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override.with.default", + "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") + res := icmd.RunCmd(cmd) + assert.Equal(t, strings.TrimSpace(res.Stdout()), "EnvFileDefaultValue") + }) + + // No Compose file and env variable pass to the run command + // 1. Command Line (docker compose run --env ) <-- Result expected + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive // 5. Variable is not defined t.Run("shell priority from run command", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", - projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", - "WHEREAMI=shell-run", "env-compose-priority") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override", + "run", "--rm", "-e", "WHEREAMI=shell-run", "env-compose-priority") assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell-run") }) - // No Compose file & no env variable but override env file - // 1. Compose file - // 2. Shell environment variables - // 3. Environment file <-- Result expected - // 4. Dockerfile + // No Compose file & no env variable but override env file + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment patched by .env as a default --env-file value) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive // 5. Variable is not defined - t.Run("override env file", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", - projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e", - "WHEREAMI", "env-compose-priority") - assert.Equal(t, strings.TrimSpace(res.Stdout()), "override") - }) - - // No Compose file & no env variable but override env file - // 1. Compose file - // 2. Shell environment variables - // 3. Environment file <-- Result expected - // 4. Dockerfile - // 5. Variable is not defined - t.Run("env file", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", - projectDir, "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") + t.Run("override env file from compose", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env-file.yaml", + "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") assert.Equal(t, strings.TrimSpace(res.Stdout()), "Env File") }) - // No Compose file & no env variable, using an empty override env file - // 1. Compose file - // 2. Shell environment variables - // 3. Environment file - // 4. Dockerfile <-- Result expected + // No Compose file & no env variable but override by default env file + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment patched by --env-file value) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("override env file", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.override", + "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "override") + }) + + // No Compose file & no env variable but override env file + // 1. Command Line (docker compose run --env ) <-- Result expected (From environment patched by --env-file value) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("env file", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") + assert.Equal(t, strings.TrimSpace(res.Stdout()), "Env File") + }) + + // No Compose file & no env variable, using an empty override env file + // 1. Command Line (docker compose run --env ) + // 2. Compose File (service::environment section) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive <-- Result expected // 5. Variable is not defined t.Run("use Dockerfile", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory", - projectDir, "--env-file", "./fixtures/environment/env-priority/.env.empty", "run", "--rm", "-e", "WHEREAMI", - "env-compose-priority") + res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", + "--env-file", "./fixtures/environment/env-priority/.env.empty", + "run", "--rm", "-e", "WHEREAMI", "env-compose-priority") assert.Equal(t, strings.TrimSpace(res.Stdout()), "Dockerfile") }) t.Run("down", func(t *testing.T) { - c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down") + c.RunDockerComposeCmd(t, "--project-name", "env-priority", "down") }) } func TestEnvInterpolation(t *testing.T) { c := NewParallelCLI(t) - projectDir := "./fixtures/environment/env-interpolation" - - // No variable defined in the Compose file and env variable pass to the run command - // 1. Compose file - // 2. Shell environment variables <-- Result expected - // 3. Environment file - // 4. Dockerfile + // No variable defined in the Compose file and nor env variable pass to the run command + // 1. Command Line (docker compose run --env ) + // 2. Compose File (service::environment section) <-- Result expected (From environment patched by .env as a default --env-file value) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive // 5. Variable is not defined t.Run("shell priority from run command", func(t *testing.T) { - cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml", - "--project-directory", projectDir, "config") + cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml", "config") cmd.Env = append(cmd.Env, "WHEREAMI=shell") res := icmd.RunCmd(cmd) - res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`}) + res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:EnvFile`}) + }) + + // No variable defined in the Compose file and env variable pass to the run command + // 1. Command Line (docker compose run --env ) + // 2. Compose File (service::environment section) <-- Result expected (From environment patched by .env as a default --env-file value. + // This variable has a default value in case of an absent variable in the OS environment) + // 3. Compose File (service::env_file section file) + // 4. Container Image ENV directive + // 5. Variable is not defined + t.Run("shell priority from run command using default value fallback", func(t *testing.T) { + c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation-default-value/compose.yaml", "config"). + Assert(t, icmd.Expected{Out: `IMAGE: default_env:EnvFileDefaultValue`}) }) } func TestCommentsInEnvFile(t *testing.T) { c := NewParallelCLI(t) - projectDir := "./fixtures/environment/env-file-comments" - t.Run("comments in env files", func(t *testing.T) { c.RunDockerOrExitError(t, "rmi", "env-file-comments") - c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", "--project-directory", - projectDir, "up", "-d", "--build") + c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", "up", "-d", "--build") res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-file-comments/compose.yaml", - "--project-directory", projectDir, "run", "--rm", "-e", "COMMENT", "-e", "NO_COMMENT", "env-file-comments") + "run", "--rm", "-e", "COMMENT", "-e", "NO_COMMENT", "env-file-comments") res.Assert(t, icmd.Expected{Out: `COMMENT=1234`}) res.Assert(t, icmd.Expected{Out: `NO_COMMENT=1234#5`}) - c.RunDockerComposeCmd(t, "--project-directory", projectDir, "down", "--rmi", "all") + c.RunDockerComposeCmd(t, "--project-name", "env-file-comments", "down", "--rmi", "all") }) } diff --git a/pkg/e2e/compose_run_test.go b/pkg/e2e/compose_run_test.go index e1abb581..4df78325 100644 --- a/pkg/e2e/compose_run_test.go +++ b/pkg/e2e/compose_run_test.go @@ -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()) }) diff --git a/pkg/e2e/fixtures/build-test/secrets/Dockerfile b/pkg/e2e/fixtures/build-test/secrets/Dockerfile index ff47d7ba..5c2924e6 100644 --- a/pkg/e2e/fixtures/build-test/secrets/Dockerfile +++ b/pkg/e2e/fixtures/build-test/secrets/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.2 +# syntax=docker/dockerfile:1 # Copyright 2020 Docker Compose CLI authors @@ -20,3 +20,7 @@ FROM alpine RUN echo "foo" > /tmp/expected RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret > /tmp/actual RUN diff /tmp/expected /tmp/actual + +RUN echo "bar" > /tmp/expected +RUN --mount=type=secret,id=envsecret cat /run/secrets/envsecret > tmp/actual +RUN diff --ignore-all-space /tmp/expected /tmp/actual diff --git a/pkg/e2e/fixtures/build-test/secrets/compose.yml b/pkg/e2e/fixtures/build-test/secrets/compose.yml index 1bb96d31..bcdd8ae9 100644 --- a/pkg/e2e/fixtures/build-test/secrets/compose.yml +++ b/pkg/e2e/fixtures/build-test/secrets/compose.yml @@ -5,7 +5,10 @@ services: context: . secrets: - mysecret + - envsecret secrets: mysecret: file: ./secret.txt + envsecret: + environment: SOME_SECRET diff --git a/pkg/e2e/fixtures/build-test/ssh/Dockerfile b/pkg/e2e/fixtures/build-test/ssh/Dockerfile index 1a1831af..d2fe8e5b 100644 --- a/pkg/e2e/fixtures/build-test/ssh/Dockerfile +++ b/pkg/e2e/fixtures/build-test/ssh/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.2 +# syntax=docker/dockerfile:1 # Copyright 2020 Docker Compose CLI authors diff --git a/pkg/e2e/fixtures/environment/env-interpolation-default-value/.env b/pkg/e2e/fixtures/environment/env-interpolation-default-value/.env new file mode 100644 index 00000000..79a91230 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-interpolation-default-value/.env @@ -0,0 +1 @@ +IMAGE=default_env:${WHEREAMI:-EnvFileDefaultValue} diff --git a/pkg/e2e/fixtures/environment/env-interpolation-default-value/compose.yaml b/pkg/e2e/fixtures/environment/env-interpolation-default-value/compose.yaml new file mode 100644 index 00000000..4d02fcda --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-interpolation-default-value/compose.yaml @@ -0,0 +1,6 @@ +services: + env-interpolation: + image: bash + environment: + IMAGE: ${IMAGE} + command: echo "$IMAGE" diff --git a/pkg/e2e/fixtures/environment/env-interpolation/.env b/pkg/e2e/fixtures/environment/env-interpolation/.env index 87bc8ee7..b3a1dfee 100644 --- a/pkg/e2e/fixtures/environment/env-interpolation/.env +++ b/pkg/e2e/fixtures/environment/env-interpolation/.env @@ -1,2 +1,2 @@ -WHEREAMI=Env File -IMAGE=default_env:${WHEREAMI} \ No newline at end of file +WHEREAMI=EnvFile +IMAGE=default_env:${WHEREAMI} diff --git a/pkg/e2e/fixtures/environment/env-priority/.env.override.with.default b/pkg/e2e/fixtures/environment/env-priority/.env.override.with.default new file mode 100644 index 00000000..35258b20 --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/.env.override.with.default @@ -0,0 +1 @@ +WHEREAMI=${WHEREAMI:-EnvFileDefaultValue} diff --git a/pkg/e2e/fixtures/environment/env-priority/compose-with-env-file.yaml b/pkg/e2e/fixtures/environment/env-priority/compose-with-env-file.yaml new file mode 100644 index 00000000..4659830f --- /dev/null +++ b/pkg/e2e/fixtures/environment/env-priority/compose-with-env-file.yaml @@ -0,0 +1,7 @@ +services: + env-compose-priority: + image: env-compose-priority + build: + context: . + env_file: + - .env.override diff --git a/pkg/e2e/fixtures/network-test/compose.yaml b/pkg/e2e/fixtures/network-test/compose.yaml index 0045ec7b..497c8bff 100644 --- a/pkg/e2e/fixtures/network-test/compose.yaml +++ b/pkg/e2e/fixtures/network-test/compose.yaml @@ -8,6 +8,8 @@ services: image: gtardif/sentences-db networks: - dbnet + - closesnetworkname1 + - closesnetworkname2 words: image: gtardif/sentences-api ports: @@ -28,3 +30,7 @@ networks: dbnet: servicenet: name: microservices + closesnetworkname1: + name: closenamenet + closesnetworkname2: + name: closenamenet-2 diff --git a/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml b/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml index aba0bf47..7e179571 100644 --- a/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml +++ b/pkg/e2e/fixtures/project-volume-bind-test/docker-compose.yml @@ -3,10 +3,10 @@ services: image: nginx container_name: frontend volumes: - - project_data:/data + - project-data:/data volumes: - project_data: + project-data: driver: local driver_opts: type: none diff --git a/pkg/e2e/fixtures/start-stop/other.yaml b/pkg/e2e/fixtures/start-stop/other.yaml new file mode 100644 index 00000000..58782726 --- /dev/null +++ b/pkg/e2e/fixtures/start-stop/other.yaml @@ -0,0 +1,5 @@ +services: + a-different-one: + image: nginx:alpine + and-another-one: + image: nginx:alpine diff --git a/pkg/e2e/fixtures/ups-deps-stop/compose.yaml b/pkg/e2e/fixtures/ups-deps-stop/compose.yaml new file mode 100644 index 00000000..c99087f6 --- /dev/null +++ b/pkg/e2e/fixtures/ups-deps-stop/compose.yaml @@ -0,0 +1,11 @@ +services: + dependency: + image: alpine + init: true + command: /bin/sh -c 'while true; do echo "hello dependency"; sleep 1; done' + + app: + depends_on: ['dependency'] + image: alpine + init: true + command: /bin/sh -c 'while true; do echo "hello app"; sleep 1; done' diff --git a/pkg/e2e/fixtures/ups-deps-stop/orphan.yaml b/pkg/e2e/fixtures/ups-deps-stop/orphan.yaml new file mode 100644 index 00000000..69e50e39 --- /dev/null +++ b/pkg/e2e/fixtures/ups-deps-stop/orphan.yaml @@ -0,0 +1,5 @@ +services: + orphan: + image: alpine + init: true + command: /bin/sh -c 'while true; do echo "hello orphan"; sleep 1; done' diff --git a/pkg/e2e/framework.go b/pkg/e2e/framework.go index 15eed455..66a6233a 100644 --- a/pkg/e2e/framework.go +++ b/pkg/e2e/framework.go @@ -46,13 +46,16 @@ var ( // DockerScanExecutableName is the OS dependent Docker CLI binary name DockerScanExecutableName = "docker-scan" + + // WindowsExecutableSuffix is the Windows executable suffix + WindowsExecutableSuffix = ".exe" ) func init() { if runtime.GOOS == "windows" { - DockerExecutableName = DockerExecutableName + ".exe" - DockerComposeExecutableName = DockerComposeExecutableName + ".exe" - DockerScanExecutableName = DockerScanExecutableName + ".exe" + DockerExecutableName += WindowsExecutableSuffix + DockerComposeExecutableName += WindowsExecutableSuffix + DockerScanExecutableName += WindowsExecutableSuffix } } @@ -124,7 +127,7 @@ func initializePlugins(t testing.TB, configDir string) { } }) - require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0755), + require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0o755), "Failed to create cli-plugins directory") composePlugin, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) if os.IsNotExist(err) { @@ -169,12 +172,12 @@ func CopyFile(t testing.TB, sourceFile string, destinationFile string) { src, err := os.Open(sourceFile) require.NoError(t, err, "Failed to open source file: %s") - // nolint: errcheck + //nolint: errcheck defer src.Close() - dst, err := os.OpenFile(destinationFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + dst, err := os.OpenFile(destinationFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755) require.NoError(t, err, "Failed to open destination file: %s", destinationFile) - // nolint: errcheck + //nolint: errcheck defer dst.Close() _, err = io.Copy(dst, src) @@ -213,7 +216,7 @@ func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) ic // MetricsSocket get the path where test metrics will be sent func (c *CLI) MetricsSocket() string { - return filepath.Join(c.ConfigDir, "./docker-cli.sock") + return filepath.Join(c.ConfigDir, "docker-cli.sock") } // NewDockerCmd creates a docker cmd without running it diff --git a/pkg/e2e/networks_test.go b/pkg/e2e/networks_test.go index 2fa84bd6..9264c76c 100644 --- a/pkg/e2e/networks_test.go +++ b/pkg/e2e/networks_test.go @@ -17,6 +17,7 @@ package e2e import ( + "fmt" "net/http" "strings" "testing" @@ -30,10 +31,10 @@ func TestNetworks(t *testing.T) { // fixture is shared with TestNetworkModes and is not safe to run concurrently c := NewCLI(t) - const projectName = "network_e2e" + const projectName = "network-e2e" t.Run("ensure we do not reuse previous networks", func(t *testing.T) { - c.RunDockerOrExitError(t, "network", "rm", projectName+"_dbnet") + c.RunDockerOrExitError(t, "network", "rm", projectName+"-dbnet") c.RunDockerOrExitError(t, "network", "rm", "microservices") }) @@ -134,7 +135,7 @@ func TestIPAMConfig(t *testing.T) { t.Run("ensure service get fixed IP assigned", func(t *testing.T) { res := c.RunDockerCmd(t, "inspect", projectName+"-foo-1", "-f", - "{{ .NetworkSettings.Networks."+projectName+"_default.IPAddress }}") + fmt.Sprintf(`{{ $network := index .NetworkSettings.Networks "%s_default" }}{{ $network.IPAMConfig.IPv4Address }}`, projectName)) res.Assert(t, icmd.Expected{Out: "10.1.0.100"}) }) diff --git a/pkg/e2e/scan_message_test.go b/pkg/e2e/scan_message_test.go index 1515efd0..789eda0a 100644 --- a/pkg/e2e/scan_message_test.go +++ b/pkg/e2e/scan_message_test.go @@ -37,7 +37,7 @@ func TestDisplayScanMessageAfterBuild(t *testing.T) { t.Run("display on compose build", func(t *testing.T) { res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-compose-build", "build") - defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-compose-build_nginx") + defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-compose-build-nginx") res.Assert(t, icmd.Expected{Err: utils.ScanSuggestMsg}) }) @@ -45,16 +45,16 @@ func TestDisplayScanMessageAfterBuild(t *testing.T) { res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-quiet", "build", "--quiet") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) - res = c.RunDockerCmd(t, "rmi", "-f", "scan-msg-test-quiet_nginx") + res = c.RunDockerCmd(t, "rmi", "-f", "scan-msg-test-quiet-nginx") assert.Assert(t, !strings.Contains(res.Combined(), "No such image")) res = c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test-q", "build", "-q") - defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-q_nginx") + defer c.RunDockerOrExitError(t, "rmi", "-f", "scan-msg-test-q-nginx") assert.Assert(t, !strings.Contains(res.Combined(), "docker scan"), res.Combined()) }) - _ = c.RunDockerOrExitError(t, "rmi", "scan-msg-test_nginx") + _ = c.RunDockerOrExitError(t, "rmi", "scan-msg-test-nginx") t.Run("display on compose up if image is built", func(t *testing.T) { res := c.RunDockerComposeCmd(t, "-f", "fixtures/simple-build-test/compose.yaml", "-p", "scan-msg-test", "up", @@ -71,9 +71,9 @@ func TestDisplayScanMessageAfterBuild(t *testing.T) { }) t.Run("do not display if scan already invoked", func(t *testing.T) { - _ = os.MkdirAll(filepath.Join(c.ConfigDir, "scan"), 0755) + _ = os.MkdirAll(filepath.Join(c.ConfigDir, "scan"), 0o755) scanConfigFile := filepath.Join(c.ConfigDir, "scan", "config.json") - err := os.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0644) + err := os.WriteFile(scanConfigFile, []byte(`{"optin":true}`), 0o644) assert.NilError(t, err) res := c.RunDockerCmd(t, "build", "-t", "test-image-scan-msg", "fixtures/simple-build-test/nginx-build") diff --git a/pkg/e2e/start_stop_test.go b/pkg/e2e/start_stop_test.go index bbfade1f..1a16d089 100644 --- a/pkg/e2e/start_stop_test.go +++ b/pkg/e2e/start_stop_test.go @@ -246,3 +246,19 @@ func TestStartStopMultipleServices(t *testing.T) { fmt.Sprintf("Missing start message for %s\n%s", svc, res.Combined())) } } + +func TestStartStopMultipleFiles(t *testing.T) { + cli := NewParallelCLI(t, WithEnv("COMPOSE_PROJECT_NAME=e2e-start-stop-svc-multiple-files")) + t.Cleanup(func() { + cli.RunDockerComposeCmd(t, "-p", "e2e-start-stop-svc-multiple-files", "down", "--remove-orphans") + }) + + cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "up", "-d") + cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/other.yaml", "up", "-d") + + res := cli.RunDockerComposeCmd(t, "-f", "./fixtures/start-stop/compose.yaml", "stop") + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-simple-1 Stopped"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-another-1 Stopped"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-a-different-one-1 Stopped"), res.Combined()) + assert.Assert(t, !strings.Contains(res.Combined(), "Container e2e-start-stop-svc-multiple-files-and-another-one-1 Stopped"), res.Combined()) +} diff --git a/pkg/e2e/up_test.go b/pkg/e2e/up_test.go index f0be9151..c0ba517b 100644 --- a/pkg/e2e/up_test.go +++ b/pkg/e2e/up_test.go @@ -1,5 +1,5 @@ /* - Copyright 2020 Docker Compose CLI authors + 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. @@ -17,8 +17,14 @@ package e2e import ( + "context" + "os/exec" + "syscall" "testing" + "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gotest.tools/v3/icmd" ) @@ -31,3 +37,69 @@ func TestUpServiceUnhealthy(t *testing.T) { c.RunDockerComposeCmd(t, "--project-name", projectName, "down") } + +func TestUpDependenciesNotStopped(t *testing.T) { + c := NewParallelCLI(t, WithEnv( + "COMPOSE_PROJECT_NAME=up-deps-stop", + )) + + reset := func() { + c.RunDockerComposeCmdNoCheck(t, "down", "-t=0", "--remove-orphans", "-v") + } + reset() + t.Cleanup(reset) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + t.Log("Launching orphan container (background)") + c.RunDockerComposeCmd(t, + "-f=./fixtures/ups-deps-stop/orphan.yaml", + "up", + "--wait", + "--detach", + "orphan", + ) + RequireServiceState(t, c, "orphan", "running") + + t.Log("Launching app container with implicit dependency") + var upOut lockedBuffer + var upCmd *exec.Cmd + go func() { + testCmd := c.NewDockerComposeCmd(t, + "-f=./fixtures/ups-deps-stop/compose.yaml", + "up", + "app", + ) + cmd := exec.CommandContext(ctx, testCmd.Command[0], testCmd.Command[1:]...) + cmd.Env = testCmd.Env + cmd.Stdout = &upOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + + assert.NoError(t, cmd.Start(), "Failed to run compose up") + upCmd = cmd + }() + + t.Log("Waiting for containers to be in running state") + upOut.RequireEventuallyContains(t, "hello app") + RequireServiceState(t, c, "app", "running") + RequireServiceState(t, c, "dependency", "running") + + t.Log("Simulating Ctrl-C") + require.NoError(t, syscall.Kill(-upCmd.Process.Pid, syscall.SIGINT), + "Failed to send SIGINT to compose up process") + + time.AfterFunc(5*time.Second, cancel) + + t.Log("Waiting for `compose up` to exit") + err := upCmd.Wait() + if err != nil { + exitErr := err.(*exec.ExitError) + require.EqualValues(t, exitErr.ExitCode(), 130) + } + + RequireServiceState(t, c, "app", "exited") + // dependency should still be running + RequireServiceState(t, c, "dependency", "running") + RequireServiceState(t, c, "orphan", "running") +} diff --git a/pkg/e2e/volumes_test.go b/pkg/e2e/volumes_test.go index ecce19e1..604b3ba6 100644 --- a/pkg/e2e/volumes_test.go +++ b/pkg/e2e/volumes_test.go @@ -35,8 +35,8 @@ func TestLocalComposeVolume(t *testing.T) { t.Run("up with build and no image name, volume", func(t *testing.T) { // ensure local test run does not reuse previously build image - c.RunDockerOrExitError(t, "rmi", "compose-e2e-volume_nginx") - c.RunDockerOrExitError(t, "volume", "rm", projectName+"_staticVol") + c.RunDockerOrExitError(t, "rmi", "compose-e2e-volume-nginx") + c.RunDockerOrExitError(t, "volume", "rm", projectName+"-staticVol") c.RunDockerOrExitError(t, "volume", "rm", "myvolume") c.RunDockerComposeCmd(t, "--project-directory", "fixtures/volume-test", "--project-name", projectName, "up", "-d") @@ -50,7 +50,7 @@ func TestLocalComposeVolume(t *testing.T) { t.Run("check container volume specs", func(t *testing.T) { res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}") output := res.Stdout() - // nolint + //nolint assert.Assert(t, strings.Contains(output, `"Destination":"/usr/src/app/node_modules","Driver":"local","Mode":"z","RW":true,"Propagation":""`), output) assert.Assert(t, strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output) }) @@ -68,7 +68,7 @@ func TestLocalComposeVolume(t *testing.T) { t.Run("check container bind-mounts specs", func(t *testing.T) { res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}") output := res.Stdout() - // nolint + //nolint assert.Assert(t, strings.Contains(output, `"Type":"bind"`)) assert.Assert(t, strings.Contains(output, `"Destination":"/usr/share/nginx/html"`)) }) @@ -88,7 +88,7 @@ func TestLocalComposeVolume(t *testing.T) { t.Run("cleanup volume project", func(t *testing.T) { c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "--volumes") ls := c.RunDockerCmd(t, "volume", "ls").Stdout() - assert.Assert(t, !strings.Contains(ls, projectName+"_staticVol")) + assert.Assert(t, !strings.Contains(ls, projectName+"-staticVol")) assert.Assert(t, !strings.Contains(ls, "myvolume")) }) } @@ -103,11 +103,11 @@ func TestProjectVolumeBind(t *testing.T) { t.Run("up on project volume with bind specification", func(t *testing.T) { tmpDir, err := os.MkdirTemp("", projectName) assert.NilError(t, err) - defer os.RemoveAll(tmpDir) // nolint + defer os.RemoveAll(tmpDir) //nolint c.RunDockerComposeCmd(t, "--project-name", projectName, "down") - c.RunDockerOrExitError(t, "volume", "rm", "-f", projectName+"_project_data").Assert(t, icmd.Success) + c.RunDockerOrExitError(t, "volume", "rm", "-f", projectName+"_project-data").Assert(t, icmd.Success) cmd := c.NewCmdWithEnv([]string{"TEST_DIR=" + tmpDir}, "docker", "compose", "--project-directory", "fixtures/project-volume-bind-test", "--project-name", projectName, "up", "-d") icmd.RunCmd(cmd).Assert(t, icmd.Success) diff --git a/pkg/progress/event.go b/pkg/progress/event.go index 5a013a8b..0ead54dd 100644 --- a/pkg/progress/event.go +++ b/pkg/progress/event.go @@ -44,99 +44,99 @@ type Event struct { } // ErrorMessageEvent creates a new Error Event with message -func ErrorMessageEvent(ID string, msg string) Event { - return NewEvent(ID, Error, msg) +func ErrorMessageEvent(id string, msg string) Event { + return NewEvent(id, Error, msg) } // ErrorEvent creates a new Error Event -func ErrorEvent(ID string) Event { - return NewEvent(ID, Error, "Error") +func ErrorEvent(id string) Event { + return NewEvent(id, Error, "Error") } // CreatingEvent creates a new Create in progress Event -func CreatingEvent(ID string) Event { - return NewEvent(ID, Working, "Creating") +func CreatingEvent(id string) Event { + return NewEvent(id, Working, "Creating") } // StartingEvent creates a new Starting in progress Event -func StartingEvent(ID string) Event { - return NewEvent(ID, Working, "Starting") +func StartingEvent(id string) Event { + return NewEvent(id, Working, "Starting") } // StartedEvent creates a new Started in progress Event -func StartedEvent(ID string) Event { - return NewEvent(ID, Done, "Started") +func StartedEvent(id string) Event { + return NewEvent(id, Done, "Started") } // Waiting creates a new waiting event -func Waiting(ID string) Event { - return NewEvent(ID, Working, "Waiting") +func Waiting(id string) Event { + return NewEvent(id, Working, "Waiting") } // Healthy creates a new healthy event -func Healthy(ID string) Event { - return NewEvent(ID, Done, "Healthy") +func Healthy(id string) Event { + return NewEvent(id, Done, "Healthy") } // Exited creates a new exited event -func Exited(ID string) Event { - return NewEvent(ID, Done, "Exited") +func Exited(id string) Event { + return NewEvent(id, Done, "Exited") } // RestartingEvent creates a new Restarting in progress Event -func RestartingEvent(ID string) Event { - return NewEvent(ID, Working, "Restarting") +func RestartingEvent(id string) Event { + return NewEvent(id, Working, "Restarting") } // RestartedEvent creates a new Restarted in progress Event -func RestartedEvent(ID string) Event { - return NewEvent(ID, Done, "Restarted") +func RestartedEvent(id string) Event { + return NewEvent(id, Done, "Restarted") } // RunningEvent creates a new Running in progress Event -func RunningEvent(ID string) Event { - return NewEvent(ID, Done, "Running") +func RunningEvent(id string) Event { + return NewEvent(id, Done, "Running") } // CreatedEvent creates a new Created (done) Event -func CreatedEvent(ID string) Event { - return NewEvent(ID, Done, "Created") +func CreatedEvent(id string) Event { + return NewEvent(id, Done, "Created") } // StoppingEvent creates a new Stopping in progress Event -func StoppingEvent(ID string) Event { - return NewEvent(ID, Working, "Stopping") +func StoppingEvent(id string) Event { + return NewEvent(id, Working, "Stopping") } // StoppedEvent creates a new Stopping in progress Event -func StoppedEvent(ID string) Event { - return NewEvent(ID, Done, "Stopped") +func StoppedEvent(id string) Event { + return NewEvent(id, Done, "Stopped") } // KillingEvent creates a new Killing in progress Event -func KillingEvent(ID string) Event { - return NewEvent(ID, Working, "Killing") +func KillingEvent(id string) Event { + return NewEvent(id, Working, "Killing") } // KilledEvent creates a new Killed in progress Event -func KilledEvent(ID string) Event { - return NewEvent(ID, Done, "Killed") +func KilledEvent(id string) Event { + return NewEvent(id, Done, "Killed") } // RemovingEvent creates a new Removing in progress Event -func RemovingEvent(ID string) Event { - return NewEvent(ID, Working, "Removing") +func RemovingEvent(id string) Event { + return NewEvent(id, Working, "Removing") } // RemovedEvent creates a new removed (done) Event -func RemovedEvent(ID string) Event { - return NewEvent(ID, Done, "Removed") +func RemovedEvent(id string) Event { + return NewEvent(id, Done, "Removed") } // NewEvent new event -func NewEvent(ID string, status EventStatus, statusText string) Event { +func NewEvent(id string, status EventStatus, statusText string) Event { return Event{ - ID: ID, + ID: id, Status: status, StatusText: statusText, } diff --git a/pkg/progress/tty.go b/pkg/progress/tty.go index a94d659d..0dc95b90 100644 --- a/pkg/progress/tty.go +++ b/pkg/progress/tty.go @@ -164,14 +164,14 @@ func (w *ttyWriter) print() { continue } line := lineText(event, "", terminalWidth, statusPadding, runtime.GOOS != "windows") - // nolint: errcheck + //nolint: errcheck fmt.Fprint(w.out, line) numLines++ for _, v := range w.eventIDs { ev := w.events[v] if ev.ParentID == event.ID { line := lineText(ev, " ", terminalWidth, statusPadding, runtime.GOOS != "windows") - // nolint: errcheck + //nolint: errcheck fmt.Fprint(w.out, line) numLines++ } diff --git a/scripts/validate/fileheader b/scripts/validate/fileheader index 8b503df3..abb30b03 100755 --- a/scripts/validate/fileheader +++ b/scripts/validate/fileheader @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# Copyright Docker Compose CLI authors +# Copyright 2020,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. @@ -16,12 +16,12 @@ set -eu -o pipefail -if ! command -v ltag; then - >&2 echo "ERROR: ltag not found. Install with:" - >&2 echo " go get -u github.com/kunalkushwaha/ltag" +if ! command -v addlicense; then + >&2 echo "ERROR: addlicense not found. Install with:" + >&2 echo " go install -u github.com/google/addlicense@latest" exit 1 fi BASEPATH="${1-}" -ltag -t "${BASEPATH}scripts/validate/template" -excludes "validate testdata resolvepath" --check -v \ No newline at end of file +find . -regex '.*\.sh' -o -regex '.*\.go' -o -regex '.*Makefile' -o -regex '.*Dockerfile' | xargs addlicense -check -l apache -c 'Docker Compose CLI authors' -ignore validate -ignore testdata -ignore resolvepath -v 1>&2 \ No newline at end of file