diff --git a/.dockerignore b/.dockerignore index d5b28dafb..b052cccd9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ .cache .claude +.docker-cache .idea .omc .playwright-mcp diff --git a/.github/actions/docker-cache/action.yml b/.github/actions/docker-cache/action.yml new file mode 100644 index 000000000..250fecf31 --- /dev/null +++ b/.github/actions/docker-cache/action.yml @@ -0,0 +1,45 @@ +name: Docker build cache +description: > + Restores the Dockerfile's Go and npm cache mounts and persists them afterwards. + BuildKit cache mounts live in the builder daemon and are not covered by any + cache exporter, so they have to be injected and extracted explicitly. Requires + Buildx to be set up and must run before the build. + +inputs: + builder: + description: Buildx builder name + required: true + cache-scope: + description: > + Cache namespace, mirroring build-toolchain. "main" (default) writes the + shared cache. Untrusted callers (e.g. PR builds) should pass a different + value such as "pr": writes stay isolated so they cannot poison the shared + cache, while reads still fall back to it. + default: main + +runs: + using: composite + steps: + # Rotates with the dependency set. Source changes keep using the existing + # cache, which still covers the third-party packages dominating the build. + - name: Cache mount contents + id: cache + uses: actions/cache@v6 + with: + path: .docker-cache + key: ${{ runner.os }}-docker-mounts-${{ inputs.cache-scope }}-${{ hashFiles('go.sum', 'package-lock.json') }} + restore-keys: | + ${{ runner.os }}-docker-mounts-${{ inputs.cache-scope }}- + ${{ runner.os }}-docker-mounts-main- + + - name: Inject cache mounts + uses: reproducible-containers/buildkit-cache-dance@5422eac04292c961a382e0f584ea0f03ad9da723 # v3.4.0 + with: + builder: ${{ inputs.builder }} + cache-map: | + { + ".docker-cache/go-build": "/root/.cache/go-build", + ".docker-cache/go-mod": "/root/.cache/go-mod", + ".docker-cache/npm": "/root/.npm" + } + skip-extraction: ${{ steps.cache.outputs.cache-hit }} diff --git a/.github/workflows/command-pr-build.yml b/.github/workflows/command-pr-build.yml index c6b711edc..e0120dec0 100644 --- a/.github/workflows/command-pr-build.yml +++ b/.github/workflows/command-pr-build.yml @@ -129,8 +129,15 @@ jobs: password: ${{ secrets.DOCKER_PASS }} - name: Setup Buildx + id: buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 + - name: Restore build cache + uses: ./.github/actions/docker-cache + with: + builder: ${{ steps.buildx.outputs.name }} + cache-scope: pr + - name: Publish uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7 with: diff --git a/.github/workflows/nightly-docker.yml b/.github/workflows/nightly-docker.yml index c6706a09d..9db513a49 100644 --- a/.github/workflows/nightly-docker.yml +++ b/.github/workflows/nightly-docker.yml @@ -28,8 +28,14 @@ jobs: password: ${{ secrets.DOCKER_PASS }} - name: Setup Buildx + id: buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 + - name: Restore build cache + uses: ./.github/actions/docker-cache + with: + builder: ${{ steps.buildx.outputs.name }} + - name: Define tags id: meta uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 486cfd4ff..622d37156 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,8 +60,14 @@ jobs: password: ${{ secrets.DOCKER_PASS }} - name: Setup Buildx + id: buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 + - name: Restore build cache + uses: ./.github/actions/docker-cache + with: + builder: ${{ steps.buildx.outputs.name }} + - name: Meta id: meta uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6 diff --git a/Dockerfile b/Dockerfile index e224d4f30..7dafc4a83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,12 +49,12 @@ RUN --mount=type=cache,target=${GOMODCACHE} go mod download COPY Makefile . COPY cmd/implement/ cmd/implement/ COPY api/ api/ -RUN --mount=type=cache,target=${GOMODCACHE} make install +RUN --mount=type=cache,target=${GOMODCACHE} --mount=type=cache,target=${GOCACHE} make install # prepare COPY . . RUN make patch-asn1 -RUN --mount=type=cache,target=${GOMODCACHE} make assets +RUN --mount=type=cache,target=${GOMODCACHE} --mount=type=cache,target=${GOCACHE} make assets # copy ui COPY --from=node /build/dist /build/dist