Quellcode durchsuchen

Better sandboxed workflow and enhanced cross compilation

Signed-off-by: CrazyMax <[email protected]>
CrazyMax vor 3 Jahren
Ursprung
Commit
5ec20296e4

+ 0 - 1
.dockerignore

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

+ 171 - 79
.github/workflows/ci.yml

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

+ 0 - 45
.github/workflows/release.yaml

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

+ 0 - 1
.gitignore

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

+ 1 - 0
.golangci.yml

@@ -1,5 +1,6 @@
 run:
   concurrency: 2
+  timeout: 10m
 linters:
   enable-all: false
   disable-all: true

+ 3 - 2
BUILDING.md

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

+ 152 - 77
Dockerfile

@@ -15,98 +15,173 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-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 \
-    git \
-    docker \
-    make \
-    protoc \
-    protobuf-dev
+ARG GO_VERSION=1.18.5
+ARG XX_VERSION=1.1.2
+ARG GOLANGCI_LINT_VERSION=v1.47.3
+ARG ADDLICENSE_VERSION=v1.0.0
+
+ARG BUILD_TAGS="e2e,kube"
+ARG DOCS_FORMATS="md,yaml"
+ARG LICENSE_FILES=".*\(Dockerfile\|Makefile\|\.go\|\.hcl\|\.sh\)"
+
+# xx is a helper for cross-compilation
+FROM --platform=${BUILDPLATFORM} tonistiigi/xx:${XX_VERSION} AS xx
+
+FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint
+FROM ghcr.io/google/addlicense:${ADDLICENSE_VERSION} AS addlicense
+
+FROM --platform=${BUILDPLATFORM} golang:${GO_VERSION}-alpine AS base
+COPY --from=xx / /
+RUN apk add --no-cache \
+      docker \
+      file \
+      git \
+      protoc \
+      protobuf-dev
+WORKDIR /src
+ENV CGO_ENABLED=0
+
+FROM base AS build-base
 COPY go.* .
 RUN --mount=type=cache,target=/go/pkg/mod \
     --mount=type=cache,target=/root/.cache/go-build \
     go mod download
 
-FROM base AS lint
-ENV CGO_ENABLED=0
-COPY --from=local-golangci-lint /usr/bin/golangci-lint /usr/bin/golangci-lint
-ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
+FROM build-base AS vendored
+RUN --mount=type=bind,target=.,rw \
     --mount=type=cache,target=/go/pkg/mod \
-    --mount=type=cache,target=/root/.cache/go-build \
-    --mount=type=cache,target=/root/.cache/golangci-lint \
-    BUILD_TAGS=${BUILD_TAGS} \
-    GIT_TAG=${GIT_TAG} \
-    make -f builder.Makefile lint
-
-FROM base AS make-compose-plugin
-ENV CGO_ENABLED=0
-ARG TARGETOS
-ARG TARGETARCH
-ARG BUILD_TAGS
-ARG GIT_TAG
+    go mod tidy && mkdir /out && cp go.mod go.sum /out
+
+FROM scratch AS vendor-update
+COPY --from=vendored /out /
+
+FROM vendored AS vendor-validate
+RUN --mount=type=bind,target=.,rw <<EOT
+  set -e
+  git add -A
+  cp -rf /out/* .
+  diff=$(git status --porcelain -- go.mod go.sum)
+  if [ -n "$diff" ]; then
+    echo >&2 'ERROR: Vendor result differs. Please vendor your package with "make go-mod-tidy"'
+    echo "$diff"
+    exit 1
+  fi
+EOT
+
+FROM base AS version
 RUN --mount=target=. \
-    --mount=type=cache,target=/go/pkg/mod \
-    --mount=type=cache,target=/root/.cache/go-build \
-    GOOS=${TARGETOS} \
-    GOARCH=${TARGETARCH} \
-    BUILD_TAGS=${BUILD_TAGS} \
-    GIT_TAG=${GIT_TAG} \
-    make COMPOSE_BINARY=/out/docker-compose -f builder.Makefile compose-plugin
+    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 base AS make-cross
+FROM build-base AS build
 ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
+ARG TARGETPLATFORM
+RUN --mount=type=bind,target=. \
+    --mount=type=cache,target=/root/.cache \
     --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/* .
+    --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 scratch AS cross
-COPY --from=make-cross /out/* .
+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 base AS test
-ENV CGO_ENABLED=0
+FROM build-base AS test
+ARG CGO_ENABLED=0
 ARG BUILD_TAGS
-ARG GIT_TAG
-RUN --mount=target=. \
+RUN --mount=type=bind,target=. \
+    --mount=type=cache,target=/root/.cache \
     --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
+    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=. \
-    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
+    --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 TARGETARCH
+ARG TARGETVARIANT
+RUN --mount=from=binary \
+    mkdir -p /out && \
+    # TODO: should just use standard arch
+    TARGETARCH=$([ "$TARGETARCH" = "amd64" ] && echo "x86_64" || echo "$TARGETARCH"); \
+    TARGETARCH=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "$TARGETARCH"); \
+    cp docker-compose* "/out/docker-compose-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}$(ls docker-compose* | sed -e 's/^docker-compose//')" && \
+    (cd /out ; for f in *; do shasum --binary --algorithm 256 $f | tee -a /out/checksums.txt > $f.sha256; done)
+
+FROM scratch AS release
+COPY --from=releaser /out/ /
 
 # docs-reference is a target used as remote context to update docs on release
 # with latest changes on docker.github.io.

+ 25 - 30
Makefile

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

+ 0 - 73
builder.Makefile

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

+ 124 - 0
docker-bake.hcl

@@ -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"]
+}

+ 0 - 57
docs/Dockerfile

@@ -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 - 2
pkg/e2e/framework.go

@@ -129,7 +129,7 @@ func initializePlugins(t testing.TB, configDir string) {
 
 	require.NoError(t, os.MkdirAll(filepath.Join(configDir, "cli-plugins"), 0o755),
 		"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) {
 		t.Logf("WARNING: docker-compose cli-plugin not found")
 	}
@@ -302,7 +302,7 @@ func ComposeStandalonePath(t testing.TB) string {
 	if !composeStandaloneMode {
 		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)",
 		DockerComposeExecutableName)
 	return composeBinary

+ 0 - 32
scripts/validate/check-go-mod

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

+ 0 - 27
scripts/validate/fileheader

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

+ 0 - 13
scripts/validate/template/bash.txt

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

+ 0 - 13
scripts/validate/template/dockerfile.txt

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

+ 0 - 16
scripts/validate/template/go.txt

@@ -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.
-*/
-

+ 0 - 13
scripts/validate/template/makefile.txt

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