name: buildkit

# Default to 'contents: read', which grants actions to read commits.
#
# If any permission is set, any permission not included in the list is
# implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

on:
  workflow_dispatch:
  push:
    branches:
      - 'master'
      - '[0-9]+.[0-9]+'
      - '[0-9]+.x'
  pull_request:

env:
  GO_VERSION: "1.24.3"
  DESTDIR: ./build
  SETUP_BUILDX_VERSION: edge
  SETUP_BUILDKIT_IMAGE: moby/buildkit:latest

jobs:
  validate-dco:
    uses: ./.github/workflows/.dco.yml

  build-linux:
    runs-on: ubuntu-24.04
    timeout-minutes: 120 # guardrails timeout for the whole job
    needs:
      - validate-dco
    steps:
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        with:
          version: ${{ env.SETUP_BUILDX_VERSION }}
          driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
          buildkitd-flags: --debug
      -
        name: Build
        uses: docker/bake-action@v6
        with:
          targets: binary
      -
        name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: binary
          path: ${{ env.DESTDIR }}
          if-no-files-found: error
          retention-days: 1

  test-linux:
    runs-on: ubuntu-24.04
    timeout-minutes: 120 # guardrails timeout for the whole job
    needs:
      - build-linux
    env:
      TEST_IMAGE_BUILD: "0"
      TEST_IMAGE_ID: "buildkit-tests"
    strategy:
      fail-fast: false
      matrix:
        worker:
          - dockerd
          - dockerd-containerd
        pkg:
          - client
          - cmd/buildctl
          - solver
          - frontend
          - frontend/dockerfile
        typ:
          - integration
    steps:
      -
        name: Prepare
        run: |
          disabledFeatures="cache_backend_azblob,cache_backend_s3"
          if [ "${{ matrix.worker }}" = "dockerd" ]; then
            disabledFeatures="${disabledFeatures},merge_diff"
          fi
          echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
      # Expose `ACTIONS_RUNTIME_TOKEN` and `ACTIONS_CACHE_URL`, which is used
      # in BuildKit's test suite to skip/unskip cache exporters:
      # https://github.com/moby/buildkit/blob/567a99433ca23402d5e9b9f9124005d2e59b8861/client/client_test.go#L5407-L5411
      -
        name: Expose GitHub Runtime
        uses: crazy-max/ghaction-github-runtime@v3
      -
        name: Checkout
        uses: actions/checkout@v4
        with:
          path: moby
      -
        name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache-dependency-path: vendor.sum
      -
        name: BuildKit ref
        run: |
          echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
        working-directory: moby
      -
        name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
        uses: actions/checkout@v4
        with:
          repository: ${{ env.BUILDKIT_REPO }}
          ref: ${{ env.BUILDKIT_REF }}
          path: buildkit
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        with:
          version: ${{ env.SETUP_BUILDX_VERSION }}
          driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
          buildkitd-flags: --debug
      -
        name: Download binary artifacts
        uses: actions/download-artifact@v4
        with:
          name: binary
          path: ./buildkit/build/moby/
      -
        name: Update daemon.json
        run: |
          sudo rm -f /etc/docker/daemon.json
          sudo service docker restart
          docker version
          docker info
      -
        name: Build test image
        uses: docker/bake-action@v6
        with:
          source: .
          workdir: ./buildkit
          targets: integration-tests
          set: |
            *.output=type=docker,name=${{ env.TEST_IMAGE_ID }}
      -
        name: Test
        run: |
          ./hack/test ${{ matrix.typ }}
        env:
          CONTEXT: "."
          TEST_DOCKERD: "1"
          TEST_DOCKERD_BINARY: "./build/moby/dockerd"
          TESTPKGS: "./${{ matrix.pkg }}"
          TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=${{ matrix.worker }}$"
        working-directory: buildkit

  build-windows:
    runs-on: windows-2022
    timeout-minutes: 120
    needs:
      - validate-dco
    env:
      GOPATH: ${{ github.workspace }}\go
      GOBIN: ${{ github.workspace }}\go\bin
      BIN_OUT: ${{ github.workspace }}\out
      WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
      WINDOWS_BASE_TAG_2022: ltsc2022
      TEST_IMAGE_NAME: moby:test
      TEST_CTN_NAME: moby
    defaults:
      run:
        working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          path: ${{ env.GOPATH }}/src/github.com/docker/docker

      - name: Env
        run: |
          Get-ChildItem Env: | Out-String
      - name: Moby - Init
        run: |
          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
          echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache-dependency-path: vendor.sum
      - name: Cache
        uses: actions/cache@v4
        with:
          path: |
            ~\AppData\Local\go-build
            ~\go\pkg\mod
            ${{ github.workspace }}\go-build
            ${{ env.GOPATH }}\pkg\mod
          key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
          restore-keys: |
            ${{ inputs.os }}-${{ github.job }}-

      - name: Docker info
        run: |
          docker info

      - name: Build base image
        run: |
          & docker build `
            --build-arg WINDOWS_BASE_IMAGE `
            --build-arg WINDOWS_BASE_IMAGE_TAG `
            --build-arg GO_VERSION `
            -t ${{ env.TEST_IMAGE_NAME }} `
            -f Dockerfile.windows .

      - name: Build binaries
        run: |
          & docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
              -v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
              -v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
              ${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
          go install github.com/distribution/distribution/v3/cmd/registry@latest

      - name: Checkout BuildKit
        uses: actions/checkout@v4
        with:
          repository: moby/buildkit
          ref: master
          path: buildkit

      - name: Add buildctl to binaries
        run: |
          go install ./cmd/buildctl
        working-directory: buildkit

      - name: Copy artifacts
        run: |
          New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
          cp ${{ env.GOPATH }}\bin\registry.exe ${{ env.BIN_OUT }}
          cp ${{ env.GOPATH }}\bin\buildctl.exe ${{ env.BIN_OUT }}

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-windows
          path: ${{ env.BIN_OUT }}/*
          if-no-files-found: error
          retention-days: 2

  test-windows:
    runs-on: windows-2022
    timeout-minutes: 120 # guardrails timeout for the whole job
    needs:
      - build-windows
    env:
      TEST_IMAGE_BUILD: "0"
      TEST_IMAGE_ID: "buildkit-tests"
      GOPATH: ${{ github.workspace }}\go
      GOBIN: ${{ github.workspace }}\go\bin
      BIN_OUT: ${{ github.workspace }}\out
      TESTFLAGS: "-v --timeout=90m"
      TEST_DOCKERD: "1"
    strategy:
      fail-fast: false
      matrix:
        worker:
          - dockerd-containerd
        pkg:
          - ./client#1-4
          - ./client#2-4
          - ./client#3-4
          - ./client#4-4
          - ./cmd/buildctl
          - ./frontend
          - ./frontend/dockerfile#1-12
          - ./frontend/dockerfile#2-12
          - ./frontend/dockerfile#3-12
          - ./frontend/dockerfile#4-12
          - ./frontend/dockerfile#5-12
          - ./frontend/dockerfile#6-12
          - ./frontend/dockerfile#7-12
          - ./frontend/dockerfile#8-12
          - ./frontend/dockerfile#9-12
          - ./frontend/dockerfile#10-12
          - ./frontend/dockerfile#11-12
          - ./frontend/dockerfile#12-12
    steps:
      - name: Prepare
        shell: bash
        run: |
          disabledFeatures="cache_backend_azblob,cache_backend_s3"
          if [ "${{ matrix.worker }}" = "dockerd" ]; then
            disabledFeatures="${disabledFeatures},merge_diff"
          fi
          echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
      - name: Expose GitHub Runtime
        uses: crazy-max/ghaction-github-runtime@v3
      - name: Checkout
        uses: actions/checkout@v4
        with:
          path: moby
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache-dependency-path: vendor.sum
      - name: BuildKit ref
        shell: bash
        run: |
          echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
        working-directory: moby
      - name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
        uses: actions/checkout@v4
        with:
          repository: ${{ env.BUILDKIT_REPO }}
          ref: ${{ env.BUILDKIT_REF }}
          path: buildkit

      - name: Download Moby artifacts
        uses: actions/download-artifact@v4
        with:
          name: build-windows
          path: ${{ env.BIN_OUT }}

      - name: Add binaries to PATH
        run: |
          ls ${{ env.BIN_OUT }}
          Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

      - name: Test Prep
        shell: bash
        run: |
          TESTPKG=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $1}')
          echo "TESTPKG=$TESTPKG" >> $GITHUB_ENV
          echo "TEST_REPORT_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.worker }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
          testFlags="${{ env.TESTFLAGS }}"
          testSlice=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $2}')
          testSliceOffset=""
          if [ -n "$testSlice" ]; then
           testSliceOffset="slice=$testSlice/"
          fi
          if [ -n "${{ matrix.worker }}" ]; then
           testFlags="${testFlags} --run=TestIntegration/$testSliceOffset.*/worker=${{ matrix.worker }}"
          fi
          echo "TESTFLAGS=${testFlags}" >> $GITHUB_ENV
      - name: Test
        shell: bash
        run: |
          mkdir -p ./bin/testreports
          gotestsum \
            --jsonfile="./bin/testreports/go-test-report-${{ env.TEST_REPORT_NAME }}.json" \
            --junitfile="./bin/testreports/junit-report-${{ env.TEST_REPORT_NAME }}.xml" \
            --packages="${{ env.TESTPKG }}" \
            -- \
              "-mod=vendor" \
              "-coverprofile" "./bin/testreports/coverage-${{ env.TEST_REPORT_NAME }}.txt" \
              "-covermode" "atomic" ${{ env.TESTFLAGS }}
        working-directory: buildkit
