diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml new file mode 100644 index 0000000000..94259e522b --- /dev/null +++ b/.github/workflows/merge.yml @@ -0,0 +1,71 @@ +name: merge + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - 'v2' + tags: + - 'v*' + workflow_dispatch: + +jobs: + e2e: + name: Build and test + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + os: [desktop-windows, desktop-macos, desktop-m1] + # mode: [plugin, standalone] + mode: [plugin] + env: + GO111MODULE: "on" + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-go@v3 + with: + go-version-file: go.mod + cache: true + check-latest: true + + - name: List Docker resources on machine + run: | + docker ps --all + docker volume ls + docker network ls + docker image ls + - name: Remove Docker resources on machine + continue-on-error: true + run: | + docker kill $(docker ps -q) + docker rm -f $(docker ps -aq) + docker volume rm -f $(docker volume ls -q) + docker ps --all + + - name: Unit tests + run: make test + + - name: Build binaries + run: | + make + - name: Check arch of go compose binary + run: | + file ./bin/build/docker-compose + if: ${{ !contains(matrix.os, 'desktop-windows') }} + - + name: Test plugin mode + if: ${{ matrix.mode == 'plugin' }} + run: | + make e2e-compose + - + name: Test standalone mode + if: ${{ matrix.mode == 'standalone' }} + run: | + make e2e-compose-standalone + diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml deleted file mode 100644 index ea0556dcca..0000000000 --- a/.github/workflows/rebase.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Automatic Rebase -on: - issue_comment: - types: [created] -jobs: - rebase: - name: Rebase - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') - runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - uses: actions/checkout@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - fetch-depth: 0 # otherwise, you will fail to push refs to dest repo - - name: Automatic Rebase - uses: cirrus-actions/rebase@1.4 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Makefile b/Makefile index 675cb04bd4..1e53b14c87 100644 --- a/Makefile +++ b/Makefile @@ -18,13 +18,20 @@ VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags) GO_LDFLAGS ?= -s -w -X ${PKG}/internal.Version=${VERSION} GO_BUILDTAGS ?= e2e,kube -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Linux) +ifeq ($(OS),Windows_NT) + DETECTED_OS = Windows +else + DETECTED_OS = $(shell uname -s) +endif +ifeq ($(DETECTED_OS),Linux) MOBY_DOCKER=/usr/bin/docker endif -ifeq ($(UNAME_S),Darwin) +ifeq ($(DETECTED_OS),Darwin) MOBY_DOCKER=/Applications/Docker.app/Contents/Resources/bin/docker endif +ifeq ($(DETECTED_OS),Windows) + BINARY_EXT=.exe +endif TEST_FLAGS?= E2E_TEST?= @@ -40,7 +47,7 @@ all: build .PHONY: build ## Build the compose cli-plugin build: - CGO_ENABLED=0 GO111MODULE=on go build -trimpath -tags "$(GO_BUILDTAGS)" -ldflags "$(GO_LDFLAGS)" -o "$(DESTDIR)/docker-compose" ./cmd + CGO_ENABLED=0 GO111MODULE=on go build -trimpath -tags "$(GO_BUILDTAGS)" -ldflags "$(GO_LDFLAGS)" -o "$(DESTDIR)/docker-compose$(BINARY_EXT)" ./cmd .PHONY: binary binary: diff --git a/pkg/e2e/buffer.go b/pkg/e2e/buffer.go index 787e6c358f..b97b81d01b 100644 --- a/pkg/e2e/buffer.go +++ b/pkg/e2e/buffer.go @@ -60,7 +60,7 @@ func (l *lockedBuffer) RequireEventuallyContains(t testing.TB, v string) { "Error: %v", err) } return strings.Contains(bufContents.String(), v) - }, 2*time.Second, 20*time.Millisecond, + }, 5*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 0620f6e583..9be7f5b2f3 100644 --- a/pkg/e2e/build_test.go +++ b/pkg/e2e/build_test.go @@ -18,6 +18,7 @@ package e2e import ( "net/http" + "runtime" "strings" "testing" "time" @@ -85,6 +86,51 @@ func TestLocalComposeBuild(t *testing.T) { res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`}) }) + t.Run("build as part of up", func(t *testing.T) { + c.RunDockerOrExitError(t, "rmi", "build-test-nginx") + c.RunDockerOrExitError(t, "rmi", "custom-nginx") + + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") + t.Cleanup(func() { + c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down") + }) + + res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) + res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) + + 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", "custom-nginx") + }) + + t.Run("no rebuild when up again", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") + + assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout()) + }) + + t.Run("rebuild when up --build", func(t *testing.T) { + res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build") + + res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) + res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) + }) + + 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", "custom-nginx") + }) +} + +func TestBuildSSH(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Running on Windows. Skipping...") + } + c := NewParallelCLI(t) + t.Run("build failed with ssh default value", func(t *testing.T) { res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "") res.Assert(t, icmd.Expected{ @@ -130,47 +176,12 @@ func TestLocalComposeBuild(t *testing.T) { }) c.RunDockerCmd(t, "image", "inspect", "build-test-ssh") }) - - t.Run("build as part of up", func(t *testing.T) { - c.RunDockerOrExitError(t, "rmi", "build-test-nginx") - c.RunDockerOrExitError(t, "rmi", "custom-nginx") - - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") - t.Cleanup(func() { - c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down") - }) - - res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) - - 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", "custom-nginx") - }) - - t.Run("no rebuild when up again", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d") - - assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout()) - }) - - t.Run("rebuild when up --build", func(t *testing.T) { - res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build") - - res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"}) - res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"}) - }) - - 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", "custom-nginx") - }) } func TestBuildSecrets(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on windows") + } c := NewParallelCLI(t) t.Run("build with secrets", func(t *testing.T) { @@ -259,6 +270,9 @@ func TestBuildImageDependencies(t *testing.T) { } func TestBuildPlatformsWithCorrectBuildxConfig(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Running on Windows. Skipping...") + } c := NewParallelCLI(t) // declare builder diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index de5d3c029a..3eade16cc5 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -135,6 +135,9 @@ func TestDownComposefileInParentFolder(t *testing.T) { } func TestAttachRestart(t *testing.T) { + if _, ok := os.LookupEnv("CI"); ok { + t.Skip("Skipping test on CI... flaky") + } c := NewParallelCLI(t) cmd := c.NewDockerComposeCmd(t, "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up") @@ -146,7 +149,7 @@ func TestAttachRestart(t *testing.T) { return strings.Count(res.Stdout(), "failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n", debug) - }, 2*time.Minute, 2*time.Second) + }, 4*time.Minute, 2*time.Second) assert.Equal(t, strings.Count(res.Stdout(), "failing-1 | world"), 3, res.Combined()) } diff --git a/pkg/e2e/pause_test.go b/pkg/e2e/pause_test.go index a91c7a2028..a823814166 100644 --- a/pkg/e2e/pause_test.go +++ b/pkg/e2e/pause_test.go @@ -21,6 +21,7 @@ import ( "fmt" "net" "net/http" + "os" "testing" "time" @@ -29,6 +30,9 @@ import ( ) func TestPause(t *testing.T) { + if _, ok := os.LookupEnv("CI"); ok { + t.Skip("Skipping test on CI... flaky") + } cli := NewParallelCLI(t, WithEnv( "COMPOSE_PROJECT_NAME=e2e-pause", "COMPOSE_FILE=./fixtures/pause/compose.yaml")) @@ -46,7 +50,7 @@ func TestPause(t *testing.T) { "b": urlForService(t, cli, "b", 80), } for _, url := range urls { - HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 5*time.Second) + HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 20*time.Second) } // pause a and verify that it can no longer be hit but b still can @@ -98,7 +102,7 @@ func TestPauseServiceAlreadyPaused(t *testing.T) { // launch a and wait for it to come up cli.RunDockerComposeCmd(t, "up", "-d", "a") - HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 5*time.Second) + HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 10*time.Second) // pause a twice - first time should pass, second time fail cli.RunDockerComposeCmd(t, "pause", "a") diff --git a/pkg/e2e/up_test.go b/pkg/e2e/up_test.go index c0ba517bf8..e859829649 100644 --- a/pkg/e2e/up_test.go +++ b/pkg/e2e/up_test.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + /* Copyright 2022 Docker Compose CLI authors diff --git a/pkg/e2e/volumes_test.go b/pkg/e2e/volumes_test.go index 76a9094b9a..2c9d47c25a 100644 --- a/pkg/e2e/volumes_test.go +++ b/pkg/e2e/volumes_test.go @@ -20,6 +20,7 @@ import ( "net/http" "os" "path/filepath" + "runtime" "strings" "testing" "time" @@ -99,6 +100,9 @@ func TestProjectVolumeBind(t *testing.T) { const projectName = "compose-e2e-project-volume-bind" t.Run("up on project volume with bind specification", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Running on Windows. Skipping...") + } tmpDir, err := os.MkdirTemp("", projectName) assert.NilError(t, err) defer os.RemoveAll(tmpDir) //nolint