name: test-os

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

# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
  contents: read

on:
  schedule:
    - cron: '0 10 * * *'
  workflow_dispatch:
  push:
    branches:
      - 'master'
      - 'v[0-9]+.[0-9]+'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'docs/**'
      - 'frontend/dockerfile/docs/**'

env:
  GO_VERSION: "1.25"
  SETUP_BUILDX_VERSION: "edge"
  SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest"
  DESTDIR: "./bin"

jobs:
  build:
    runs-on: ubuntu-24.04
    strategy:
      fail-fast: false
      matrix:
        platform:
          - windows/amd64
          - freebsd/amd64
    steps:
      -
        name: Prepare
        run: |
          platform=${{ matrix.platform }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
      -
        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:
          provenance: false
          targets: binaries-for-test
          set: |
            *.platform=${{ matrix.platform }}
            *.cache-from=type=gha,scope=binaries-for-test-${{ env.PLATFORM_PAIR }}
            *.cache-to=type=gha,scope=binaries-for-test-${{ env.PLATFORM_PAIR }},repository=${{ github.repository }},ghtoken=${{ secrets.GITHUB_TOKEN }}
      -
        name: List artifacts
        run: |
          tree -nh ${{ env.DESTDIR }}
      -
        name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: buildkit-${{ env.PLATFORM_PAIR }}
          path: ${{ env.DESTDIR }}/*
          if-no-files-found: error
          retention-days: 1

  test-windows-amd64:
    runs-on: ${{ matrix.os }}
    needs:
      - build
    env:
      TESTFLAGS: "-v --timeout=60m"
      GOTESTSUM_FORMAT: "standard-verbose"
    strategy:
      fail-fast: false
      matrix:
        os: [windows-2022]
        worker:
          - containerd
        pkg:
          - ./client#1-4
          - ./client#2-4
          - ./client#3-4
          - ./client#4-4
          - ./cmd/buildctl
          - ./worker/containerd
          - ./solver
          - ./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
        include:
          - os: windows-2022
            worker: containerd
            pkg: ./...
            skip-integration-tests: 1
    steps:
      -
        name: Prepare
        run: |
          TESTPKG=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $1}')
          echo "TESTPKG=$TESTPKG" >> $GITHUB_ENV
          echo "TEST_REPORT_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.skip-integration-tests }}-${{ 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
        shell: bash
      -
        name: Checkout
        uses: actions/checkout@v5
      -
        name: Expose GitHub Runtime
        uses: crazy-max/ghaction-github-runtime@v3
      -
        name: Set up Go
        uses: actions/setup-go@v6
        with:
          go-version: "${{ env.GO_VERSION }}"
          cache: false
      -
        name: Download artifacts
        uses: actions/download-artifact@v5
        with:
          name: buildkit-windows-amd64
          path: ${{ github.workspace }}\bin
      -
        name: Add bin folder to Path
        run: |
          echo "${{ github.workspace }}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
      -
        name: Test
        env:
          TMPDIR: ${{ runner.temp }}
          SKIP_INTEGRATION_TESTS: ${{ matrix.skip-integration-tests }}
        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 }}
        shell: bash
      -
        name: Send to Codecov
        if: always()
        uses: codecov/codecov-action@v5
        with:
          directory: ./bin/testreports
          env_vars: RUNNER_OS
          flags: unit
          disable_file_fixes: true
          token: ${{ secrets.CODECOV_TOKEN }}  # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
      -
        name: Generate annotations
        if: always()
        uses: crazy-max/.github/.github/actions/gotest-annotations@fa6141aedf23596fb8bdcceab9cce8dadaa31bd9
        with:
          directory: ./bin/testreports
      -
        name: Upload test reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-reports-${{ matrix.os }}-${{ env.TEST_REPORT_NAME }}
          path: ./bin/testreports
          retention-days: 1
      -
        name: Dump context
        if: failure()
        uses: crazy-max/ghaction-dump-context@v2

  test-freebsd-amd64:
    runs-on: ubuntu-22.04
    needs:
      - build
    env:
      GOOS: freebsd
      # https://github.com/hashicorp/vagrant/issues/13652
      VAGRANT_DISABLE_STRICT_DEPENDENCY_ENFORCEMENT: 1
    steps:
      -
        name: Checkout
        uses: actions/checkout@v5
      -
        name: Download artifacts
        uses: actions/download-artifact@v5
        with:
          name: buildkit-freebsd-amd64
          path: ${{ env.DESTDIR }}
      -
        name: Cache Vagrant boxes
        uses: actions/cache@v4
        with:
          path: ~/.vagrant.d/boxes
          key: ${{ runner.os }}-vagrant-${{ hashFiles('hack/Vagrantfile.freebsd') }}
          restore-keys: |
            ${{ runner.os }}-vagrant-
      -
        name: Install vagrant
        run: |
          set -x
          wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
          echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
          sudo apt-get update
          sudo apt-get install -y libvirt-dev libvirt-daemon libvirt-daemon-system vagrant vagrant-libvirt ruby-libvirt
          sudo systemctl enable --now libvirtd
          sudo chmod a+rw /var/run/libvirt/libvirt-sock
          vagrant plugin install vagrant-libvirt
          vagrant --version
      -
        name: Set up vagrant
        run: |
          ln -sf hack/Vagrantfile.freebsd Vagrantfile
          vagrant up --no-tty
      -
        name: Smoke test
        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08  # v3.0.2
        with:
          timeout_minutes: 20
          max_attempts: 5
          command: |
            vagrant up --provision-with=test-smoke
      -
        name: BuildKit logs
        if: always()
        run: |
          vagrant ssh -- "sudo cat /vagrant/.tmp/logs/buildkitd"
      -
        name: Containerd logs
        if: always()
        run: |
          vagrant ssh -- "sudo cat /vagrant/.tmp/logs/containerd"

  sandbox-build:
    if: ${{ github.repository == 'moby/buildkit' }}
    runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
    strategy:
      fail-fast: false
      matrix:
        platform:
          - linux/amd64
          - linux/arm64
    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: integration-tests-base
          set: |
            *.platform=${{ matrix.platform }}
