Merge branch '8768-avoid-pulling-same-image-multiple-times' of github.com:KoditkarVedant/compose into 8768-avoid-pulling-same-image-multiple-times

This commit is contained in:
Vedant Koditkar 2022-08-14 16:52:17 +05:30
commit 293cf21c58
31 changed files with 553 additions and 540 deletions

View File

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

View File

@ -1,9 +1,15 @@
name: Continuous integration name: ci
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: branches:
- v2 - 'v2'
tags:
- 'v*'
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
@ -11,115 +17,201 @@ on:
description: 'To run with tmate enter "debug_enabled"' description: 'To run with tmate enter "debug_enabled"'
required: false required: false
default: "false" default: "false"
env: env:
GO_VERSION: 1.18.5 GO_VERSION: "1.18.5" # for non sandboxed e2e tests
DOCKER_CLI_VERSION: 20.10.17 DESTDIR: "./bin"
DOCKER_CLI_VERSION: "20.10.17"
jobs: jobs:
lint: prepare:
name: Lint runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.platforms.outputs.matrix }}
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Create matrix
id: platforms
run: |
echo ::set-output name=matrix::$(docker buildx bake binary-cross --print | jq -cr '.target."binary-cross".platforms')
-
name: Show matrix
run: |
echo ${{ steps.platforms.outputs.matrix }}
validate:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- lint
- validate-go-mod
- validate-headers
- validate-docs
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Run
run: |
make ${{ matrix.target }}
binary:
runs-on: ubuntu-latest
needs:
- prepare
strategy:
fail-fast: false
matrix:
platform: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
-
name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Build
uses: docker/bake-action@v2
with:
targets: release
set: |
*.platform=${{ matrix.platform }}
*.cache-from=type=gha,scope=binary-${{ env.PLATFORM_PAIR }}
*.cache-to=type=gha,scope=binary-${{ env.PLATFORM_PAIR }},mode=max
-
name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: compose
path: ${{ env.DESTDIR }}/*
if-no-files-found: error
test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code into the Go module directory -
name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
-
- name: Set up Go ${{ env.GO_VERSION }} name: Set up Docker Buildx
uses: actions/setup-go@v3 uses: docker/setup-buildx-action@v2
-
name: Test
uses: docker/bake-action@v2
with: with:
go-version: ${{ env.GO_VERSION }} targets: test
cache: true set: |
*.cache-from=type=gha,scope=test
*.cache-to=type=gha,scope=test
- name: Validate go-mod, license headers and docs are up-to-date e2e:
run: make validate runs-on: ubuntu-latest
- name: Run golangci-lint
env: env:
BUILD_TAGS: e2e DESTDIR: "./bin/build"
uses: golangci/golangci-lint-action@v3 strategy:
with: fail-fast: false
version: v1.47.3 matrix:
args: --timeout=180s mode:
- plugin
# only on main branch, costs too much for the gain on every PR - standalone
validate-cross-build:
name: Validate cross build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps: steps:
- name: Checkout code into the Go module directory -
name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
-
- name: Set up Go ${{ env.GO_VERSION }} name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
cache: true cache: true
-
# Ensure we don't discover cross platform build issues at release time. name: Setup docker CLI
# Time used to build linux here is gained back in the build for local E2E step
- name: Build packages
run: make -f builder.Makefile cross
build-plugin:
name: Build and tests in plugin mode
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Setup docker CLI
run: | run: |
curl https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.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 sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
-
- name: Test name: Build
run: make -f builder.Makefile test uses: docker/bake-action@v2
- name: Build for local E2E
env:
BUILD_TAGS: e2e
run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin
- name: E2E Test in plugin mode
run: make e2e-compose
build-standalone:
name: Build and tests in standalone mode
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with: with:
go-version: ${{ env.GO_VERSION }} targets: binary
cache: true set: |
*.cache-from=type=gha,scope=binary-linux-amd64
- name: Setup docker CLI *.cache-from=type=gha,scope=binary-e2e-${{ matrix.mode }}
run: | *.cache-to=type=gha,scope=binary-e2e-${{ matrix.mode }},mode=max
curl https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz | tar xz
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
- name: Build for local E2E
env: env:
BUILD_TAGS: e2e BUILD_TAGS: e2e
run: make GIT_TAG=e2e-PR-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} -f builder.Makefile compose-plugin -
name: Setup tmate session
- name: Setup tmate session if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }}
uses: mxschmitt/action-tmate@v3 uses: mxschmitt/action-tmate@8b4e4ac71822ed7e0ad5fb3d1c33483e9e8fb270 # v3.11
with: with:
limit-access-to-actor: true limit-access-to-actor: true
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled }} -
name: Test plugin mode
- name: E2E Test in standalone mode if: ${{ matrix.mode == 'plugin' }}
run: |
make e2e-compose
-
name: Test standalone mode
if: ${{ matrix.mode == 'standalone' }}
run: | run: |
rm -f /usr/local/bin/docker-compose rm -f /usr/local/bin/docker-compose
cp bin/docker-compose /usr/local/bin cp bin/build/docker-compose /usr/local/bin
make e2e-compose-standalone make e2e-compose-standalone
release:
runs-on: ubuntu-latest
needs:
- binary
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Download artifacts
uses: actions/download-artifact@v3
with:
name: compose
path: ${{ env.DESTDIR }}
-
name: License
run: cp packaging/* ${{ env.DESTDIR }}/
-
name: List artifacts
run: |
tree -nh ${{ env.DESTDIR }}
-
name: Check artifacts
run: |
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
-
name: GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 # v1.10.0
with:
artifacts: ${{ env.DESTDIR }}/*
generateReleaseNotes: true
draft: true
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,45 +0,0 @@
name: Releaser
on:
workflow_dispatch:
inputs:
tag:
description: "Release Tag"
required: true
env:
GO_VERSION: 1.18.5
jobs:
upload-release:
runs-on: ubuntu-latest
steps:
- name: Checkout code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Setup docker CLI
run: |
curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.17.tgz | tar xz
sudo cp ./docker/docker /usr/bin/ && rm -rf docker && docker version
- name: Build
run: make GIT_TAG=${{ github.event.inputs.tag }} -f builder.Makefile cross
- name: Compute checksums
run: cd bin; for f in *; do shasum --binary --algorithm 256 $f | tee -a checksums.txt > $f.sha256; done
- name: License
run: cp packaging/* bin/
- uses: ncipollo/release-action@v1
with:
artifacts: "bin/*"
generateReleaseNotes: true
draft: true
commit: "v2"
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event.inputs.tag }}

1
.gitignore vendored
View File

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

View File

@ -1,5 +1,6 @@
run: run:
concurrency: 2 concurrency: 2
timeout: 10m
linters: linters:
enable-all: false enable-all: false
disable-all: true disable-all: true
@ -18,6 +19,7 @@ linters:
- lll - lll
- misspell - misspell
- nakedret - nakedret
- nolintlint
- staticcheck - staticcheck
- structcheck - structcheck
- typecheck - typecheck

View File

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

View File

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

View File

@ -12,7 +12,15 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
export DOCKER_BUILDKIT=1 ifneq (, $(BUILDX_BIN))
export BUILDX_CMD = $(BUILDX_BIN)
else ifneq (, $(shell docker buildx version))
export BUILDX_CMD = docker buildx
else ifneq (, $(shell which buildx))
export BUILDX_CMD = $(which buildx)
else
$(error "Buildx is required: https://github.com/docker/buildx#installing")
endif
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux) ifeq ($(UNAME_S),Linux)
@ -35,11 +43,12 @@ all: compose-plugin
.PHONY: compose-plugin .PHONY: compose-plugin
compose-plugin: ## Compile the compose cli-plugin compose-plugin: ## Compile the compose cli-plugin
@docker build . --target compose-plugin \ $(BUILDX_CMD) bake binary
--platform local \
--build-arg BUILD_TAGS=e2e,kube \ .PHONY: install
--build-arg GIT_TAG=$(GIT_TAG) \ install: compose-plugin
--output ./bin mkdir -p ~/.docker/cli-plugins
install bin/build/docker-compose ~/.docker/cli-plugins/docker-compose
.PHONY: e2e-compose .PHONY: e2e-compose
e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test e2e-compose: ## Run end to end local tests in plugin mode. Set E2E_TEST=TestName to run a single test
@ -71,45 +80,31 @@ build-and-e2e: compose-plugin e2e-compose e2e-compose-standalone ## Compile the
.PHONY: cross .PHONY: cross
cross: ## Compile the CLI for linux, darwin and windows cross: ## Compile the CLI for linux, darwin and windows
@docker build . --target cross \ $(BUILDX_CMD) bake binary
--build-arg BUILD_TAGS \
--build-arg GIT_TAG=$(GIT_TAG) \
--output ./bin \
.PHONY: test .PHONY: test
test: ## Run unit tests test: ## Run unit tests
@docker build --progress=plain . \ $(BUILDX_CMD) bake test
--build-arg BUILD_TAGS=kube \
--build-arg GIT_TAG=$(GIT_TAG) \
--target test
.PHONY: cache-clear .PHONY: cache-clear
cache-clear: ## Clear the builder cache cache-clear: ## Clear the builder cache
@docker builder prune --force --filter type=exec.cachemount --filter=unused-for=24h $(BUILDX_CMD) prune --force --filter type=exec.cachemount --filter=unused-for=24h
.PHONY: lint .PHONY: lint
lint: ## run linter(s) lint: ## run linter(s)
@docker build . \ $(BUILDX_CMD) bake lint
--build-arg BUILD_TAGS=kube,e2e \
--build-arg GIT_TAG=$(GIT_TAG) \
--target lint
.PHONY: docs .PHONY: docs
docs: ## generate documentation docs: ## generate documentation
$(eval $@_TMP_OUT := $(shell mktemp -d -t dockercli-output.XXXXXXXXXX)) $(eval $@_TMP_OUT := $(shell mktemp -d -t compose-output.XXXXXXXXXX))
docker build . \ $(BUILDX_CMD) bake --set "*.output=type=local,dest=$($@_TMP_OUT)" docs-update
--output type=local,dest=$($@_TMP_OUT) \
-f ./docs/Dockerfile \
--target update
rm -rf ./docs/internal rm -rf ./docs/internal
cp -R "$($@_TMP_OUT)"/out/* ./docs/ cp -R "$($@_TMP_OUT)"/out/* ./docs/
rm -rf "$($@_TMP_OUT)"/* rm -rf "$($@_TMP_OUT)"/*
.PHONY: validate-docs .PHONY: validate-docs
validate-docs: ## validate the doc does not change validate-docs: ## validate the doc does not change
@docker build . \ $(BUILDX_CMD) bake docs-validate
-f ./docs/Dockerfile \
--target validate
.PHONY: check-dependencies .PHONY: check-dependencies
check-dependencies: ## check dependency updates check-dependencies: ## check dependency updates
@ -117,15 +112,15 @@ check-dependencies: ## check dependency updates
.PHONY: validate-headers .PHONY: validate-headers
validate-headers: ## Check license header for all files validate-headers: ## Check license header for all files
@docker build . --target check-license-headers $(BUILDX_CMD) bake license-validate
.PHONY: go-mod-tidy .PHONY: go-mod-tidy
go-mod-tidy: ## Run go mod tidy in a container and output resulting go.mod and go.sum go-mod-tidy: ## Run go mod tidy in a container and output resulting go.mod and go.sum
@docker build . --target go-mod-tidy --output . $(BUILDX_CMD) bake vendor-update
.PHONY: validate-go-mod .PHONY: validate-go-mod
validate-go-mod: ## Validate go.mod and go.sum are up-to-date validate-go-mod: ## Validate go.mod and go.sum are up-to-date
@docker build . --target check-go-mod $(BUILDX_CMD) bake vendor-validate
validate: validate-go-mod validate-headers validate-docs ## Validate sources validate: validate-go-mod validate-headers validate-docs ## Validate sources

View File

@ -1,6 +1,9 @@
# Docker Compose v2 # Docker Compose v2
[![Actions Status](https://github.com/docker/compose/workflows/Continuous%20integration/badge.svg)](https://github.com/docker/compose/actions) [![GitHub release](https://img.shields.io/github/release/docker/compose.svg?style=flat-square)](https://github.com/docker/compose/releases/latest)
[![PkgGoDev](https://img.shields.io/badge/go.dev-docs-007d9c?style=flat-square&logo=go&logoColor=white)](https://pkg.go.dev/github.com/docker/compose/v2)
[![Build Status](https://img.shields.io/github/workflow/status/docker/compose/ci?label=ci&logo=github&style=flat-square)](https://github.com/docker/compose/actions?query=workflow%3Aci)
[![Go Report Card](https://goreportcard.com/badge/github.com/docker/compose/v2?style=flat-square)](https://goreportcard.com/report/github.com/docker/compose/v2)
![Docker Compose](logo.png?raw=true "Docker Compose Logo") ![Docker Compose](logo.png?raw=true "Docker Compose Logo")

View File

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

View File

@ -28,6 +28,7 @@ import (
"github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/cli"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
composegoutils "github.com/compose-spec/compose-go/utils" composegoutils "github.com/compose-spec/compose-go/utils"
"github.com/docker/buildx/util/logutil"
dockercli "github.com/docker/cli/cli" dockercli "github.com/docker/cli/cli"
"github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli-plugins/manager"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
@ -250,6 +251,16 @@ func RunningAsStandalone() bool {
// RootCommand returns the compose command with its child commands // RootCommand returns the compose command with its child commands
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
// filter out useless commandConn.CloseWrite warning message that can occur
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
logrus.AddHook(logutil.NewFilter([]logrus.Level{
logrus.WarnLevel,
},
"commandConn.CloseWrite:",
"commandConn.CloseRead:",
))
opts := projectOptions{} opts := projectOptions{}
var ( var (
ansi string ansi string

View File

@ -89,7 +89,7 @@ func (l *logConsumer) Log(container, service, message string) {
} }
p := l.getPresenter(container) p := l.getPresenter(container)
for _, line := range strings.Split(message, "\n") { 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)
} }
} }

124
docker-bake.hcl Normal file
View File

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

View File

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

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/cnabio/cnab-to-oci v0.3.6 github.com/cnabio/cnab-to-oci v0.3.6
github.com/compose-spec/compose-go v1.4.0 github.com/compose-spec/compose-go v1.4.0
github.com/containerd/console v1.0.3 github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.6.7 github.com/containerd/containerd v1.6.8
github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f 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/buildx v0.8.2 // when updating, also update the replace rules accordingly
github.com/docker/cli v20.10.17+incompatible github.com/docker/cli v20.10.17+incompatible

4
go.sum
View File

@ -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.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= 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.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
github.com/containerd/containerd v1.6.7 h1:IVikHEHEMZ5SXpUa80tNGNIV7fBigjp+sOcrlzAkPCc= github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
github.com/containerd/containerd v1.6.7/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-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-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=

View File

@ -29,7 +29,6 @@ import (
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
buildx "github.com/docker/buildx/build" buildx "github.com/docker/buildx/build"
"github.com/docker/cli/cli/command/image/build" "github.com/docker/cli/cli/command/image/build"
"github.com/docker/compose/v2/pkg/api"
dockertypes "github.com/docker/docker/api/types" dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
@ -40,6 +39,8 @@ import (
"github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/pkg/urlutil"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/docker/compose/v2/pkg/api"
) )
func (s *composeService) doBuildClassic(ctx context.Context, project *types.Project, opts map[string]buildx.Options) (map[string]string, error) { func (s *composeService) doBuildClassic(ctx context.Context, project *types.Project, opts map[string]buildx.Options) (map[string]string, error) {
@ -65,7 +66,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
return nameDigests, errs return nameDigests, errs
} }
//nolint: gocyclo //nolint:gocyclo
func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options buildx.Options) (string, error) { func (s *composeService) doBuildClassicSimpleImage(ctx context.Context, options buildx.Options) (string, error) {
var ( var (
buildCtx io.ReadCloser buildCtx io.ReadCloser

View File

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

View File

@ -21,7 +21,7 @@ import (
"testing" "testing"
"github.com/compose-spec/compose-go/types" "github.com/compose-spec/compose-go/types"
"gotest.tools/v3/assert" "github.com/stretchr/testify/require"
) )
var project = types.Project{ var project = types.Project{
@ -45,25 +45,27 @@ var project = types.Project{
} }
func TestInDependencyUpCommandOrder(t *testing.T) { func TestInDependencyUpCommandOrder(t *testing.T) {
order := make(chan string) ctx, cancel := context.WithCancel(context.Background())
//nolint:errcheck, unparam t.Cleanup(cancel)
go InDependencyOrder(context.TODO(), &project, func(ctx context.Context, config string) error {
order <- config var order []string
err := InDependencyOrder(ctx, &project, func(ctx context.Context, service string) error {
order = append(order, service)
return nil return nil
}) })
assert.Equal(t, <-order, "test3") require.NoError(t, err, "Error during iteration")
assert.Equal(t, <-order, "test2") require.Equal(t, []string{"test3", "test2", "test1"}, order)
assert.Equal(t, <-order, "test1")
} }
func TestInDependencyReverseDownCommandOrder(t *testing.T) { func TestInDependencyReverseDownCommandOrder(t *testing.T) {
order := make(chan string) ctx, cancel := context.WithCancel(context.Background())
//nolint:errcheck, unparam t.Cleanup(cancel)
go InReverseDependencyOrder(context.TODO(), &project, func(ctx context.Context, config string) error {
order <- config var order []string
err := InReverseDependencyOrder(ctx, &project, func(ctx context.Context, service string) error {
order = append(order, service)
return nil return nil
}) })
assert.Equal(t, <-order, "test1") require.NoError(t, err, "Error during iteration")
assert.Equal(t, <-order, "test2") require.Equal(t, []string{"test1", "test2", "test3"}, order)
assert.Equal(t, <-order, "test3")
} }

View File

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

View File

@ -172,7 +172,7 @@ func TestDownComposefileInParentFolder(t *testing.T) {
tmpFolder, err := os.MkdirTemp("fixtures/simple-composefile", "test-tmp") tmpFolder, err := os.MkdirTemp("fixtures/simple-composefile", "test-tmp")
assert.NilError(t, err) assert.NilError(t, err)
defer os.Remove(tmpFolder) // nolint: errcheck defer os.Remove(tmpFolder) //nolint:errcheck
projectName := filepath.Base(tmpFolder) projectName := filepath.Base(tmpFolder)
res := c.RunDockerComposeCmd(t, "--project-directory", tmpFolder, "up", "-d") res := c.RunDockerComposeCmd(t, "--project-directory", tmpFolder, "up", "-d")

View File

@ -129,7 +129,7 @@ func initializePlugins(t testing.TB, configDir string) {
require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0o755), require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0o755),
"Failed to create cli-plugins directory") "Failed to create cli-plugins directory")
composePlugin, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) composePlugin, err := findExecutable(DockerComposeExecutableName, []string{"../../bin/build", "../../../bin/build"})
if os.IsNotExist(err) { if os.IsNotExist(err) {
t.Logf("WARNING: docker-compose cli-plugin not found") t.Logf("WARNING: docker-compose cli-plugin not found")
} }
@ -172,12 +172,12 @@ func CopyFile(t testing.TB, sourceFile string, destinationFile string) {
src, err := os.Open(sourceFile) src, err := os.Open(sourceFile)
require.NoError(t, err, "Failed to open source file: %s") require.NoError(t, err, "Failed to open source file: %s")
//nolint: errcheck //nolint:errcheck
defer src.Close() defer src.Close()
dst, err := os.OpenFile(destinationFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o755) 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) require.NoError(t, err, "Failed to open destination file: %s", destinationFile)
//nolint: errcheck //nolint:errcheck
defer dst.Close() defer dst.Close()
_, err = io.Copy(dst, src) _, err = io.Copy(dst, src)
@ -302,7 +302,7 @@ func ComposeStandalonePath(t testing.TB) string {
if !composeStandaloneMode { if !composeStandaloneMode {
require.Fail(t, "Not running in standalone mode") require.Fail(t, "Not running in standalone mode")
} }
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"}) composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin/build", "../../../bin/build"})
require.NoError(t, err, "Could not find standalone Compose binary (%q)", require.NoError(t, err, "Could not find standalone Compose binary (%q)",
DockerComposeExecutableName) DockerComposeExecutableName)
return composeBinary return composeBinary

View File

@ -50,7 +50,6 @@ func TestLocalComposeVolume(t *testing.T) {
t.Run("check container volume specs", func(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 }}") res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx2-1", "--format", "{{ json .Mounts }}")
output := res.Stdout() output := res.Stdout()
//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":"/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) assert.Assert(t, strings.Contains(output, `"Destination":"/myconfig","Mode":"","RW":false,"Propagation":"rprivate"`), output)
}) })
@ -68,7 +67,6 @@ func TestLocalComposeVolume(t *testing.T) {
t.Run("check container bind-mounts specs", func(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 }}") res := c.RunDockerCmd(t, "inspect", "compose-e2e-volume-nginx-1", "--format", "{{ json .Mounts }}")
output := res.Stdout() output := res.Stdout()
//nolint
assert.Assert(t, strings.Contains(output, `"Type":"bind"`)) assert.Assert(t, strings.Contains(output, `"Type":"bind"`))
assert.Assert(t, strings.Contains(output, `"Destination":"/usr/share/nginx/html"`)) assert.Assert(t, strings.Contains(output, `"Destination":"/usr/share/nginx/html"`))
}) })

View File

@ -164,14 +164,12 @@ func (w *ttyWriter) print() {
continue continue
} }
line := lineText(event, "", terminalWidth, statusPadding, runtime.GOOS != "windows") line := lineText(event, "", terminalWidth, statusPadding, runtime.GOOS != "windows")
//nolint: errcheck
fmt.Fprint(w.out, line) fmt.Fprint(w.out, line)
numLines++ numLines++
for _, v := range w.eventIDs { for _, v := range w.eventIDs {
ev := w.events[v] ev := w.events[v]
if ev.ParentID == event.ID { if ev.ParentID == event.ID {
line := lineText(ev, " ", terminalWidth, statusPadding, runtime.GOOS != "windows") line := lineText(ev, " ", terminalWidth, statusPadding, runtime.GOOS != "windows")
//nolint: errcheck
fmt.Fprint(w.out, line) fmt.Fprint(w.out, line)
numLines++ numLines++
} }

View File

@ -22,18 +22,19 @@ import (
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
) )
//nolint:errcheck
func TestSplitWriter(t *testing.T) { func TestSplitWriter(t *testing.T) {
var lines []string var lines []string
w := GetWriter(func(line string) { w := GetWriter(func(line string) {
lines = append(lines, line) lines = append(lines, line)
}) })
w.Write([]byte("h")) //nolint: errcheck w.Write([]byte("h"))
w.Write([]byte("e")) //nolint: errcheck w.Write([]byte("e"))
w.Write([]byte("l")) //nolint: errcheck w.Write([]byte("l"))
w.Write([]byte("l")) //nolint: errcheck w.Write([]byte("l"))
w.Write([]byte("o")) //nolint: errcheck w.Write([]byte("o"))
w.Write([]byte("\n")) //nolint: errcheck w.Write([]byte("\n"))
w.Write([]byte("world!\n")) //nolint: errcheck w.Write([]byte("world!\n"))
assert.DeepEqual(t, lines, []string{"hello", "world!"}) assert.DeepEqual(t, lines, []string{"hello", "world!"})
} }

View File

@ -1,32 +0,0 @@
#!/bin/sh
# Copyright 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.
set -uo pipefail
mkdir -p /tmp/gomod
cp go.* /tmp/gomod/
go mod tidy
DIFF=$(diff go.mod /tmp/gomod/go.mod && diff go.sum /tmp/gomod/go.sum)
if [ "$DIFF" ]; then
echo
echo "go.mod and go.sum are not up to date"
echo
echo "$DIFF"
echo
exit 1
else
echo "go.mod is correct"
fi;

View File

@ -1,27 +0,0 @@
#!/usr/bin/env sh
# 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.
# 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.
set -eu -o pipefail
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-}"
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

View File

@ -1,13 +0,0 @@
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@ -1,13 +0,0 @@
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

View File

@ -1,16 +0,0 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

View File

@ -1,13 +0,0 @@
# Copyright 2020 Docker Compose CLI authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.