| # reusable workflow |
| name: .windows |
| |
| # TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025 |
| |
| # 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 |
| |
| on: |
| workflow_call: |
| inputs: |
| os: |
| required: true |
| type: string |
| storage: |
| required: true |
| type: string |
| default: "graphdriver" |
| send_coverage: |
| required: false |
| type: boolean |
| default: false |
| |
| env: |
| GO_VERSION: "1.24.9" |
| GOTESTLIST_VERSION: v0.3.1 |
| TESTSTAT_VERSION: v0.1.25 |
| WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore |
| WINDOWS_BASE_TAG_2022: ltsc2022 |
| WINDOWS_BASE_TAG_2025: ltsc2025 |
| TEST_IMAGE_NAME: moby:test |
| TEST_CTN_NAME: moby |
| DOCKER_BUILDKIT: 0 |
| ITG_CLI_MATRIX_SIZE: 6 |
| |
| jobs: |
| build: |
| runs-on: ${{ inputs.os }} |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| env: |
| GOPATH: ${{ github.workspace }}\go |
| GOBIN: ${{ github.workspace }}\go\bin |
| BIN_OUT: ${{ github.workspace }}\out |
| 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: Init |
| run: | |
| New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build" |
| New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod" |
| If ("${{ inputs.os }}" -eq "windows-2025") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2025 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } ElseIf ("${{ inputs.os }}" -eq "windows-2022") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } |
| - |
| name: Docker info |
| run: | |
| docker info |
| - |
| name: Build base image |
| run: | |
| & docker build ` |
| --build-arg WINDOWS_BASE_IMAGE ` |
| --build-arg WINDOWS_BASE_IMAGE_TAG ` |
| -t ${{ env.TEST_IMAGE_NAME }} ` |
| -f Dockerfile.windows . |
| - |
| name: Build binaries |
| run: | |
| & docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" ` |
| ${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client |
| - |
| 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 }}\ |
| - |
| name: Upload artifacts |
| uses: actions/upload-artifact@v4 |
| with: |
| name: build-${{ inputs.storage }}-${{ inputs.os }} |
| path: ${{ env.BIN_OUT }}/* |
| if-no-files-found: error |
| retention-days: 2 |
| |
| unit-test: |
| runs-on: ${{ inputs.os }} |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| env: |
| GOPATH: ${{ github.workspace }}\go |
| GOBIN: ${{ github.workspace }}\go\bin |
| 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: Init |
| run: | |
| New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build" |
| New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod" |
| New-Item -ItemType "directory" -Path "bundles" |
| If ("${{ inputs.os }}" -eq "windows-2025") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2025 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } ElseIf ("${{ inputs.os }}" -eq "windows-2022") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } |
| - |
| name: Docker info |
| run: | |
| docker info |
| - |
| name: Build base image |
| run: | |
| & docker build ` |
| --build-arg WINDOWS_BASE_IMAGE ` |
| --build-arg WINDOWS_BASE_IMAGE_TAG ` |
| -t ${{ env.TEST_IMAGE_NAME }} ` |
| -f Dockerfile.windows . |
| - |
| name: Test |
| run: | |
| & docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" ` |
| -v "${{ env.GOPATH }}\src\github.com\docker\docker\bundles:C:\gopath\src\github.com\docker\docker\bundles" ` |
| ${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -TestUnit |
| - |
| name: Send to Codecov |
| if: inputs.send_coverage |
| uses: codecov/codecov-action@v4 |
| with: |
| working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker |
| directory: bundles |
| env_vars: RUNNER_OS |
| flags: unit |
| token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533 |
| - |
| name: Upload reports |
| if: always() |
| uses: actions/upload-artifact@v4 |
| with: |
| name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports |
| path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\* |
| retention-days: 1 |
| |
| unit-test-report: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| if: always() |
| needs: |
| - unit-test |
| steps: |
| - |
| name: Set up Go |
| uses: actions/setup-go@v5 |
| with: |
| go-version: ${{ env.GO_VERSION }} |
| cache: false |
| - |
| name: Download artifacts |
| uses: actions/download-artifact@v4 |
| with: |
| name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports |
| path: /tmp/artifacts |
| - |
| name: Install teststat |
| run: | |
| go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }} |
| - |
| name: Create summary |
| run: | |
| find /tmp/artifacts -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY |
| |
| integration-test-prepare: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| outputs: |
| matrix: ${{ steps.tests.outputs.matrix }} |
| steps: |
| - |
| name: Checkout |
| uses: actions/checkout@v4 |
| - |
| name: Set up Go |
| uses: actions/setup-go@v5 |
| with: |
| go-version: ${{ env.GO_VERSION }} |
| cache: false |
| - |
| name: Install gotestlist |
| run: |
| go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }} |
| - |
| name: Create matrix |
| id: tests |
| working-directory: ./integration-cli |
| run: | |
| # This step creates a matrix for integration-cli tests. Tests suites |
| # are distributed in integration-test job through a matrix. There is |
| # also an override being added to the matrix like "./..." to run |
| # "Test integration" step exclusively. |
| matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." ./...)" |
| echo "matrix=$matrix" >> $GITHUB_OUTPUT |
| - |
| name: Show matrix |
| run: | |
| echo ${{ steps.tests.outputs.matrix }} |
| |
| integration-test: |
| runs-on: ${{ inputs.os }} |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }} |
| needs: |
| - build |
| - integration-test-prepare |
| strategy: |
| fail-fast: false |
| matrix: |
| storage: |
| - ${{ inputs.storage }} |
| runtime: |
| - builtin |
| - containerd |
| test: ${{ fromJson(needs.integration-test-prepare.outputs.matrix) }} |
| exclude: |
| - storage: snapshotter |
| runtime: builtin |
| env: |
| GOPATH: ${{ github.workspace }}\go |
| GOBIN: ${{ github.workspace }}\go\bin |
| BIN_OUT: ${{ github.workspace }}\out |
| 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: Set up Go |
| uses: actions/setup-go@v5 |
| with: |
| go-version: ${{ env.GO_VERSION }} |
| cache: false |
| - |
| name: Set up Jaeger |
| run: | |
| # Jaeger is set up on Linux through the setup-tracing action. If you update Jaeger here, don't forget to |
| # update the version set in .github/actions/setup-tracing/action.yml. |
| Invoke-WebRequest -Uri "https://github.com/jaegertracing/jaeger/releases/download/v1.46.0/jaeger-1.46.0-windows-amd64.tar.gz" -OutFile ".\jaeger-1.46.0-windows-amd64.tar.gz" |
| tar -zxvf ".\jaeger-1.46.0-windows-amd64.tar.gz" |
| Start-Process '.\jaeger-1.46.0-windows-amd64\jaeger-all-in-one.exe' |
| echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| shell: pwsh |
| - |
| name: Env |
| run: | |
| Get-ChildItem Env: | Out-String |
| - |
| name: Download artifacts |
| uses: actions/download-artifact@v4 |
| with: |
| name: build-${{ inputs.storage }}-${{ inputs.os }} |
| path: ${{ env.BIN_OUT }} |
| - |
| name: Init |
| run: | |
| New-Item -ItemType "directory" -Path "bundles" |
| If ("${{ inputs.os }}" -eq "windows-2025") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2025 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } ElseIf ("${{ inputs.os }}" -eq "windows-2022") { |
| echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } |
| Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append |
| |
| $testName = ([System.BitConverter]::ToString((New-Object System.Security.Cryptography.SHA256Managed).ComputeHash([System.Text.Encoding]::UTF8.GetBytes("${{ matrix.test }}"))) -replace '-').ToLower() |
| echo "TESTREPORTS_NAME=$testName" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| - |
| # removes docker service that is currently installed on the runner. we |
| # could use Uninstall-Package but not yet available on Windows runners. |
| # more info: https://github.com/actions/virtual-environments/blob/d3a5bad25f3b4326c5666bab0011ac7f1beec95e/images/win/scripts/Installers/Install-Docker.ps1#L11 |
| name: Removing current daemon |
| run: | |
| if (Get-Service docker -ErrorAction SilentlyContinue) { |
| $dockerVersion = (docker version -f "{{.Server.Version}}") |
| Write-Host "Current installed Docker version: $dockerVersion" |
| # remove service |
| Stop-Service -Force -Name docker |
| Remove-Service -Name docker |
| # removes event log entry. we could use "Remove-EventLog -LogName -Source docker" |
| # but this cmd is not available atm |
| $ErrorActionPreference = "SilentlyContinue" |
| & reg delete "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" /f 2>&1 | Out-Null |
| $ErrorActionPreference = "Stop" |
| Write-Host "Service removed" |
| } |
| - |
| name: Starting test daemon |
| run: | |
| Write-Host "Creating service" |
| If ("${{ matrix.runtime }}" -eq "containerd") { |
| $runtimeArg="--default-runtime=io.containerd.runhcs.v1" |
| echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } |
| New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null |
| New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null |
| Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" ` |
| -ArgumentList $runtimeArg, "--debug", ` |
| "--host=npipe:////./pipe/docker_engine", ` |
| "--data-root=$env:TEMP\moby-root", ` |
| "--exec-root=$env:TEMP\moby-exec", ` |
| "--pidfile=$env:TEMP\docker.pid", ` |
| "--register-service" |
| If ("${{ inputs.storage }}" -eq "snapshotter") { |
| # Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option. |
| & reg add "HKLM\SYSTEM\CurrentControlSet\Services\docker" /v Environment /t REG_MULTI_SZ /s '@' /d TEST_INTEGRATION_USE_SNAPSHOTTER=1 |
| echo "TEST_INTEGRATION_USE_SNAPSHOTTER=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append |
| } |
| Write-Host "Starting service" |
| Start-Service -Name docker |
| Write-Host "Service started successfully!" |
| - |
| name: Waiting for test daemon to start |
| run: | |
| $tries=20 |
| Write-Host "Waiting for the test daemon to start..." |
| While ($true) { |
| $ErrorActionPreference = "SilentlyContinue" |
| & "${{ env.BIN_OUT }}\docker" version |
| $ErrorActionPreference = "Stop" |
| If ($LastExitCode -eq 0) { |
| break |
| } |
| $tries-- |
| If ($tries -le 0) { |
| Throw "Failed to get a response from the daemon" |
| } |
| Write-Host -NoNewline "." |
| Start-Sleep -Seconds 1 |
| } |
| Write-Host "Test daemon started and replied!" |
| If ("${{ matrix.runtime }}" -eq "containerd") { |
| $containerdProcesses = Get-Process -Name containerd -ErrorAction:SilentlyContinue |
| If (-not $containerdProcesses) { |
| Throw "containerd process is not running" |
| } else { |
| foreach ($process in $containerdProcesses) { |
| $processPath = (Get-Process -Id $process.Id -FileVersionInfo).FileName |
| Write-Output "Running containerd instance binary Path: $($processPath)" |
| } |
| } |
| } |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| - |
| name: Docker info |
| run: | |
| & "${{ env.BIN_OUT }}\docker" info |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| - |
| name: Building contrib/busybox |
| run: | |
| & "${{ env.BIN_OUT }}\docker" build -t busybox ` |
| --build-arg WINDOWS_BASE_IMAGE ` |
| --build-arg WINDOWS_BASE_IMAGE_TAG ` |
| .\contrib\busybox\ |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| - |
| name: List images |
| run: | |
| & "${{ env.BIN_OUT }}\docker" images |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| - |
| name: Test integration |
| if: matrix.test == './...' |
| run: | |
| .\hack\make.ps1 -TestIntegration |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| GO111MODULE: "off" |
| TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker |
| - |
| name: Test integration-cli |
| if: matrix.test != './...' |
| run: | |
| .\hack\make.ps1 -TestIntegrationCli |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| GO111MODULE: "off" |
| TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker |
| INTEGRATION_TESTRUN: ${{ matrix.test }} |
| - |
| name: Send to Codecov |
| if: inputs.send_coverage |
| uses: codecov/codecov-action@v4 |
| with: |
| working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker |
| directory: bundles |
| env_vars: RUNNER_OS |
| flags: integration,${{ matrix.runtime }} |
| token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533 |
| - |
| name: Docker info |
| run: | |
| & "${{ env.BIN_OUT }}\docker" info |
| env: |
| DOCKER_HOST: npipe:////./pipe/docker_engine |
| - |
| name: Stop daemon |
| if: always() |
| run: | |
| $ErrorActionPreference = "SilentlyContinue" |
| Stop-Service -Force -Name docker |
| $ErrorActionPreference = "Stop" |
| - |
| # as the daemon is registered as a service we have to check the event |
| # logs against the docker provider. |
| name: Daemon event logs |
| if: always() |
| run: | |
| Get-WinEvent -ea SilentlyContinue ` |
| -FilterHashtable @{ProviderName= "docker"; LogName = "application"} | |
| Sort-Object @{Expression="TimeCreated";Descending=$false} | |
| ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"} | |
| Tee-Object -file ".\bundles\daemon.log" |
| - |
| name: Download Jaeger traces |
| if: always() |
| run: | |
| Invoke-WebRequest ` |
| -Uri "http://127.0.0.1:16686/api/traces?service=integration-test-client" ` |
| -OutFile ".\bundles\jaeger-trace.json" |
| - |
| name: Upload reports |
| if: always() |
| uses: actions/upload-artifact@v4 |
| with: |
| name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }} |
| path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\* |
| retention-days: 1 |
| |
| integration-test-report: |
| runs-on: ubuntu-24.04 |
| timeout-minutes: 120 # guardrails timeout for the whole job |
| continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }} |
| if: always() |
| needs: |
| - integration-test |
| strategy: |
| fail-fast: false |
| matrix: |
| storage: |
| - ${{ inputs.storage }} |
| runtime: |
| - builtin |
| - containerd |
| exclude: |
| - storage: snapshotter |
| runtime: builtin |
| steps: |
| - |
| name: Set up Go |
| uses: actions/setup-go@v5 |
| with: |
| go-version: ${{ env.GO_VERSION }} |
| cache: false |
| - |
| name: Download reports |
| uses: actions/download-artifact@v4 |
| with: |
| path: /tmp/reports |
| pattern: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-* |
| merge-multiple: true |
| - |
| name: Install teststat |
| run: | |
| go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }} |
| - |
| name: Create summary |
| run: | |
| find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY |