Browse Source

Merge pull request #43479 from crazy-max/gha-win-tests

ci: github action workflow for windows
Sebastiaan van Stijn 3 years ago
parent
commit
235f86270d

+ 411 - 0
.github/workflows/windows.yml

@@ -0,0 +1,411 @@
+name: windows
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - 'master'
+      - '[0-9]+.[0-9]{2}'
+    tags:
+      - 'v*'
+  pull_request:
+
+env:
+  GO_VERSION: 1.18.2
+  WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
+  WINDOWS_BASE_TAG_2019: ltsc2019
+  WINDOWS_BASE_TAG_2022: ltsc2022
+  TEST_IMAGE_NAME: moby:test
+  TEST_CTN_NAME: moby
+  DOCKER_BUILDKIT: 0
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - windows-2019
+          - windows-2022
+    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@v3
+        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 ("${{ matrix.os }}" -eq "windows-2019") {
+            echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+          } ElseIf ("${{ matrix.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: Cache
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~\AppData\Local\go-build
+            ~\go\pkg\mod
+            ${{ github.workspace }}\go-build
+            ${{ env.GOPATH }}\pkg\mod
+          key: ${{ matrix.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
+          restore-keys: |
+            ${{ matrix.os }}-${{ github.job }}-
+      -
+        name: Docker info
+        run: |
+          docker info
+      -
+        name: Build base image
+        run: |
+          docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
+          docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
+          docker build --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
+      -
+        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@v3
+        with:
+          name: build-${{ matrix.os }}
+          path: ${{ env.BIN_OUT }}/*
+          if-no-files-found: error
+          retention-days: 2
+
+  unit-test:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - windows-2019
+          - windows-2022
+    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@v3
+        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 ("${{ matrix.os }}" -eq "windows-2019") {
+            echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+          } ElseIf ("${{ matrix.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: Cache
+        uses: actions/cache@v3
+        with:
+          path: |
+            ~\AppData\Local\go-build
+            ~\go\pkg\mod
+            ${{ github.workspace }}\go-build
+            ${{ env.GOPATH }}\pkg\mod
+          key: ${{ matrix.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
+          restore-keys: |
+            ${{ matrix.os }}-${{ github.job }}-
+      -
+        name: Docker info
+        run: |
+          docker info
+      -
+        name: Build base image
+        run: |
+          docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
+          docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
+          docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
+      -
+        name: Test
+        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" `
+            -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: matrix.os == 'windows-2022'
+        uses: codecov/codecov-action@v3
+        with:
+          working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
+          directory: bundles
+          env_vars: RUNNER_OS
+          flags: unit
+      -
+        name: Upload reports
+        if: matrix.os == 'windows-2022'
+        uses: actions/upload-artifact@v3
+        with:
+          name: unit-reports
+          path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
+
+  integration-test:
+    runs-on: ${{ matrix.os }}
+    needs:
+      - build
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - windows-2019
+          - windows-2022
+        runtime:
+          - builtin
+          - containerd
+    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@v3
+        with:
+          path: ${{ env.GOPATH }}/src/github.com/docker/docker
+      -
+        name: Env
+        run: |
+          Get-ChildItem Env: | Out-String
+      -
+        name: Download artifacts
+        uses: actions/download-artifact@v3
+        with:
+          name: build-${{ matrix.os }}
+          path: ${{ env.BIN_OUT }}
+      -
+        name: Init
+        run: |
+          If ("${{ matrix.os }}" -eq "windows-2019") {
+            echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+          } ElseIf ("${{ matrix.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
+      -
+        # 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 only available since windows-2022
+            $ErrorActionPreference = "SilentlyContinue"
+            & reg delete "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" /f 2>&1 | Out-Null
+            $ErrorActionPreference = "Stop"
+            Write-Host "Service removed"
+          }
+      -
+        name: Starting containerd
+        if: matrix.runtime == 'containerd'
+        run: |
+          Write-Host "Generating config"
+          & "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
+          Write-Host "Creating service"
+          New-Item -ItemType Directory "$env:TEMP\ctn-root" -ErrorAction SilentlyContinue | Out-Null
+          New-Item -ItemType Directory "$env:TEMP\ctn-state" -ErrorAction SilentlyContinue | Out-Null
+          Start-Process -Wait "${{ env.BIN_OUT }}\containerd.exe" `
+            -ArgumentList "--log-level=debug", `
+              "--config=$env:TEMP\ctn.toml", `
+              "--address=\\.\pipe\containerd-containerd", `
+              "--root=$env:TEMP\ctn-root", `
+              "--state=$env:TEMP\ctn-state", `
+              "--log-file=$env:TEMP\ctn.log", `
+              "--register-service"
+          Write-Host "Starting service"
+          Start-Service -Name containerd
+          Start-Sleep -Seconds 5
+          Write-Host "Service started successfully!"
+      -
+        name: Starting test daemon
+        run: |
+          Write-Host "Creating service"
+          If ("${{ matrix.runtime }}" -eq "containerd") {
+            $runtimeArg="--containerd=\\.\pipe\containerd-containerd"
+            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"
+          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!"
+        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: Set up Go
+        uses: actions/setup-go@v3
+        with:
+          go-version: ${{ env.GO_VERSION }}
+      -
+        name: Test API
+        run: |
+          .\hack\make.ps1 -TestIntegration
+        env:
+          DOCKER_HOST: npipe:////./pipe/docker_engine
+          GO111MODULE: "off"
+          TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
+      -
+        name: Test CLI
+        run: |
+          & gotestsum --format=standard-verbose --packages="./integration-cli/..." -- `
+            "-coverprofile" "./bundles/coverage-report-int-cli-tests.txt" `
+            "-covermode" "atomic" `
+            "-tags" "autogen" `
+            "-test.timeout" "200m"
+        env:
+          DOCKER_HOST: npipe:////./pipe/docker_engine
+          GO111MODULE: "off"
+          TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
+      -
+        name: Send to Codecov
+        if: matrix.os == 'windows-2022'
+        uses: codecov/codecov-action@v3
+        with:
+          working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
+          directory: bundles
+          env_vars: RUNNER_OS
+          flags: integration,${{ matrix.runtime }}
+      -
+        name: Upload reports
+        if: matrix.os == 'windows-2022'
+        uses: actions/upload-artifact@v3
+        with:
+          name: integration-reports-${{ matrix.runtime }}
+          path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
+      -
+        name: Docker info
+        run: |
+          & "${{ env.BIN_OUT }}\docker" info
+        env:
+          DOCKER_HOST: npipe:////./pipe/docker_engine
+      -
+        name: Stop containerd
+        if: always() && matrix.runtime == 'containerd'
+        run: |
+          $ErrorActionPreference = "SilentlyContinue"
+          Stop-Service -Force -Name containerd
+          $ErrorActionPreference = "Stop"
+      -
+        name: Containerd logs
+        if: always() && matrix.runtime == 'containerd'
+        run: |
+          Get-Content "$env:TEMP\ctn.log" | Out-Host
+      -
+        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"} |
+              Select-Object -Property TimeCreated, @{N='Detailed Message'; E={$_.Message}} |
+              Sort-Object @{Expression="TimeCreated";Descending=$false} |
+              Select-Object -ExpandProperty 'Detailed Message'

+ 7 - 3
codecov.yml

@@ -1,5 +1,8 @@
-comment:
-  layout: header, changes, diff, sunburst
+comment: false
+
+github_checks:
+  annotations: false
+
 coverage:
   status:
     patch:
@@ -13,5 +16,6 @@ coverage:
         target: auto
         threshold: "15%"
     changes: false
+
 ignore:
-  - "vendor/*"
+  - "vendor/**/*"

+ 6 - 2
hack/make.ps1

@@ -328,7 +328,10 @@ Function Run-UnitTests() {
     $pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/integration"
     $pkgList = $pkgList -replace "`r`n", " "
 
-    $goTestArg = "--format=standard-verbose --jsonfile=bundles\go-test-report-unit-tests.json --junitfile=bundles\junit-report-unit-tests.xml -- " + $raceParm + " -cover -ldflags -w -a """ + "-test.timeout=10m" + """ $pkgList"
+    $jsonFilePath = $bundlesDir + "\go-test-report-unit-tests.json"
+    $xmlFilePath = $bundlesDir + "\junit-report-unit-tests.xml"
+    $coverageFilePath = $bundlesDir + "\coverage-report-unit-tests.txt"
+    $goTestArg = "--format=standard-verbose --jsonfile=$jsonFilePath --junitfile=$xmlFilePath -- " + $raceParm + " -coverprofile=$coverageFilePath -covermode=atomic -ldflags -w -a """ + "-test.timeout=10m" + """ $pkgList"
     Write-Host "INFO: Invoking unit tests run with $GOTESTSUM_LOCATION\gotestsum.exe $goTestArg"
     $pinfo = New-Object System.Diagnostics.ProcessStartInfo
     $pinfo.FileName = "$GOTESTSUM_LOCATION\gotestsum.exe"
@@ -364,13 +367,14 @@ Function Run-IntegrationTests() {
         }
         $jsonFilePath = $bundlesDir + "\go-test-report-int-tests-$normDir" + ".json"
         $xmlFilePath = $bundlesDir + "\junit-report-int-tests-$normDir" + ".xml"
+        $coverageFilePath = $bundlesDir + "\coverage-report-int-tests-$normDir" + ".txt"
         Set-Location $dir
         Write-Host "Running $($PWD.Path)"
         $pinfo = New-Object System.Diagnostics.ProcessStartInfo
         $pinfo.FileName = "gotestsum.exe"
         $pinfo.WorkingDirectory = "$($PWD.Path)"
         $pinfo.UseShellExecute = $false
-        $pinfo.Arguments = "--format=standard-verbose --jsonfile=$jsonFilePath --junitfile=$xmlFilePath -- -test.timeout=60m $env:INTEGRATION_TESTFLAGS"
+        $pinfo.Arguments = "--format=standard-verbose --jsonfile=$jsonFilePath --junitfile=$xmlFilePath -- -coverprofile=$coverageFilePath -covermode=atomic -test.timeout=60m $env:INTEGRATION_TESTFLAGS"
         $p = New-Object System.Diagnostics.Process
         $p.StartInfo = $pinfo
         $p.Start() | Out-Null

+ 3 - 0
integration-cli/docker_cli_restart_test.go

@@ -11,6 +11,7 @@ import (
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 	"gotest.tools/v3/poll"
+	"gotest.tools/v3/skip"
 )
 
 func (s *DockerSuite) TestRestartStoppedContainer(c *testing.T) {
@@ -171,6 +172,7 @@ func (s *DockerSuite) TestRestartContainerSuccess(c *testing.T) {
 	// such that it assumes there is a host process to kill. In Hyper-V
 	// containers, the process is inside the utility VM, not on the host.
 	if DaemonIsWindows() {
+		skip.If(c, testEnv.GitHubActions())
 		testRequires(c, testEnv.DaemonInfo.Isolation.IsProcess)
 	}
 
@@ -247,6 +249,7 @@ func (s *DockerSuite) TestRestartPolicyAfterRestart(c *testing.T) {
 	// such that it assumes there is a host process to kill. In Hyper-V
 	// containers, the process is inside the utility VM, not on the host.
 	if DaemonIsWindows() {
+		skip.If(c, testEnv.GitHubActions())
 		testRequires(c, testEnv.DaemonInfo.Isolation.IsProcess)
 	}
 

+ 3 - 0
integration-cli/docker_cli_run_test.go

@@ -4151,6 +4151,9 @@ func (s *DockerSuite) TestRunEmptyEnv(c *testing.T) {
 
 // #28658
 func (s *DockerSuite) TestSlowStdinClosing(c *testing.T) {
+	if DaemonIsWindows() {
+		skip.If(c, testEnv.GitHubActions())
+	}
 	const repeat = 3 // regression happened 50% of the time
 	for i := 0; i < repeat; i++ {
 		c.Run(strconv.Itoa(i), func(c *testing.T) {

+ 4 - 10
integration-cli/docker_cli_start_test.go

@@ -186,14 +186,8 @@ func (s *DockerSuite) TestStartAttachWithRename(c *testing.T) {
 }
 
 func (s *DockerSuite) TestStartReturnCorrectExitCode(c *testing.T) {
-	dockerCmd(c, "create", "--restart=on-failure:2", "--name", "withRestart", "busybox", "sh", "-c", "exit 11")
-	dockerCmd(c, "create", "--rm", "--name", "withRm", "busybox", "sh", "-c", "exit 12")
-
-	out, exitCode, err := dockerCmdWithError("start", "-a", "withRestart")
-	assert.ErrorContains(c, err, "")
-	assert.Equal(c, exitCode, 11, fmt.Sprintf("out: %s", out))
-
-	out, exitCode, err = dockerCmdWithError("start", "-a", "withRm")
-	assert.ErrorContains(c, err, "")
-	assert.Equal(c, exitCode, 12, fmt.Sprintf("out: %s", out))
+	cli.DockerCmd(c, "create", "--restart=on-failure:2", "--name", "withRestart", "busybox", "sh", "-c", "exit 11")
+	cli.DockerCmd(c, "create", "--rm", "--name", "withRm", "busybox", "sh", "-c", "exit 12")
+	cli.Docker(cli.Args("start", "-a", "withRestart")).Assert(c, icmd.Expected{ExitCode: 11})
+	cli.Docker(cli.Args("start", "-a", "withRm")).Assert(c, icmd.Expected{ExitCode: 12})
 }

+ 5 - 0
testutil/environment/environment.go

@@ -221,3 +221,8 @@ func EnsureFrozenImagesLinux(testEnv *Execution) error {
 	}
 	return nil
 }
+
+// GitHubActions is true if test is executed on a GitHub Runner.
+func (e *Execution) GitHubActions() bool {
+	return os.Getenv("GITHUB_ACTIONS") == "true"
+}