feat(snapshot): add workspace snapshots #2807
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Pull Request | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| pull_request: | |
| # Cancel in-flight runs for the same PR when a new commit is pushed. | |
| # Non-PR events (main pushes, workflow_dispatch) get a unique group per | |
| # run so they bypass concurrency entirely and run independently. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| go: ${{ steps.filter.outputs.go }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4 | |
| id: filter | |
| with: | |
| filters: | | |
| go: | |
| - '**/*.go' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - '.goreleaser.yml' | |
| - 'e2e/**' | |
| - '.github/workflows/pr-ci.yml' | |
| - 'hack/licenses/**' | |
| - 'THIRD_PARTY_LICENSES.md' | |
| precommit: | |
| name: Pre-commit | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: j178/prek-action@4e14d07f9231acabce116ccfca13b13dd9755ece # v3.0.0 | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: setup Go | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 | |
| with: | |
| go-version-file: go.mod | |
| - name: golangci-lint | |
| uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9 | |
| with: | |
| version: v2.12.2 | |
| only-new-issues: true | |
| can-read-secret: | |
| name: Can Read Secret | |
| runs-on: ubuntu-latest | |
| outputs: | |
| secret-set: ${{ steps.check-secret.outputs.secret-set }} | |
| steps: | |
| - name: Check secret | |
| id: check-secret | |
| run: | | |
| if [ -z "${{ secrets.DEVSY_GITHUB_APP_ID }}" ]; then | |
| echo "secret-set=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "secret-set=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| build-cli: | |
| name: Build CLI Binary on ${{ matrix.runner }} | |
| needs: [changes, precommit, lint] | |
| if: needs.changes.outputs.go == 'true' | |
| strategy: | |
| matrix: | |
| include: | |
| - runner: ubuntu-latest | |
| - runner: macos-latest | |
| - runner: windows-latest | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 | |
| with: | |
| go-version-file: go.mod | |
| - name: get operating system lowercase | |
| id: os | |
| shell: bash | |
| run: | | |
| OS=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]') | |
| if [ "$OS" == "macos" ]; then | |
| OS="darwin" | |
| fi | |
| echo "runner_os=$OS" >> "$GITHUB_OUTPUT" | |
| - uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7 | |
| with: | |
| distribution: goreleaser | |
| version: "~> v2" | |
| args: build --id devsy-${{ steps.os.outputs.runner_os }} --snapshot | |
| env: | |
| DEVSY_CLI_VERSION: v0.0.0 | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: devsy-${{ steps.os.outputs.runner_os }} | |
| path: dist/devsy-${{ steps.os.outputs.runner_os }}_*/devsy-${{ steps.os.outputs.runner_os }}-* | |
| - name: build e2e test binary | |
| if: matrix.runner == 'ubuntu-latest' || matrix.runner == 'windows-latest' | |
| shell: bash | |
| working-directory: ./e2e | |
| env: | |
| CGO_ENABLED: 0 | |
| run: | | |
| OUT="e2e.test" | |
| if [ "${{ runner.os }}" == "Windows" ]; then | |
| OUT="e2e.test.exe" | |
| fi | |
| go test -c -o "$OUT" ./ | |
| - name: upload e2e test binary | |
| if: matrix.runner == 'ubuntu-latest' || matrix.runner == 'windows-latest' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: e2e-test-${{ steps.os.outputs.runner_os }} | |
| path: ./e2e/e2e.test* | |
| licenses: | |
| name: Third-party licenses | |
| needs: [changes, precommit, lint] | |
| if: needs.changes.outputs.go == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 | |
| with: | |
| go-version-file: go.mod | |
| - name: Check license policy and attribution | |
| run: go run ./hack/licenses --check | |
| integration-tests-unprivileged: | |
| name: Test ${{ matrix.label }} on ${{ matrix.runner }} | |
| needs: [changes, build-cli] | |
| if: needs.changes.outputs.go == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - label: context | |
| runner: ubuntu-latest | |
| - label: extends | |
| runner: ubuntu-latest | |
| - label: outdated | |
| runner: ubuntu-latest | |
| - label: machine | |
| runner: ubuntu-latest | |
| - label: self-update | |
| runner: ubuntu-latest | |
| - label: upgrade | |
| runner: ubuntu-latest | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: get operating system lowercase | |
| id: os | |
| shell: bash | |
| run: | | |
| OS=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]') | |
| echo "runner_os=$OS" >> "$GITHUB_OUTPUT" | |
| - name: download CLI artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: devsy-${{ steps.os.outputs.runner_os }} | |
| path: ${{ runner.temp }}/devsy-bin/ | |
| merge-multiple: true | |
| - name: download e2e test binary | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: e2e-test-${{ steps.os.outputs.runner_os }} | |
| path: ./e2e/ | |
| - name: setup executable | |
| shell: bash | |
| working-directory: ./e2e | |
| run: | | |
| TEMP_DIR="${{ runner.temp }}" | |
| ls -R "$TEMP_DIR/devsy-bin/" | |
| mkdir -p ./bin/ | |
| find "$TEMP_DIR/devsy-bin/" -type f -name "devsy-*" -exec cp {} ./bin \; | |
| find ./bin -name "devsy-*" -exec chmod +x {} \; | |
| chmod +x ./e2e.test | |
| ls -R ./bin/ | |
| - name: run test | |
| shell: bash | |
| working-directory: ./e2e | |
| env: | |
| GH_USERNAME: ${{ github.repository_owner }} | |
| GH_ACCESS_TOKEN: ${{ github.token }} | |
| GH_CREDENTIAL_USERNAME: x-access-token | |
| run: | | |
| ./e2e.test -test.v -ginkgo.v -test.timeout 1500s --ginkgo.label-filter="${{ matrix.label }}" | |
| integration-tests: | |
| name: Test ${{ matrix.label }}${{ matrix.install-podman && format(' ({0})', matrix.install-podman) || '' }} on ${{ matrix.runner }} | |
| needs: [changes, can-read-secret, build-cli] | |
| if: needs.changes.outputs.go == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - label: ide | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: machine-provider | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: integration | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: tunnel | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: provider | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: false | |
| - label: ssh | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: build | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: true | |
| - label: docker-install | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: exec | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: ci | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: features | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: extends-up | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: down | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: rename | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: delivery | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: logs | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: templates | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: setup | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: run-user-commands | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: config-read | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| # Up tests | |
| - label: up-workspaces | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-behaviors | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| - label: up-handle-errors | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-private-token | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: true | |
| - label: up-provider-kubernetes | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-provider-podman | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: false | |
| requires-secret: false | |
| install-podman: rootless | |
| - label: up-provider-podman | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: false | |
| requires-secret: false | |
| install-podman: rootful | |
| - label: up-provider-docker | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-provider-microsandbox | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: false | |
| requires-secret: false | |
| install-microsandbox: true | |
| # Snapshot tests | |
| - label: snapshot | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| configure-insecure-registry: true | |
| # Up Docker Compose tests | |
| - label: up-docker-compose | |
| runner: ubuntu-latest | |
| free-disk-space: false | |
| install-kind: false | |
| requires-secret: false | |
| # Up Docker Feature tests | |
| - label: up-features | |
| runner: ubuntu-latest | |
| free-disk-space: true | |
| install-kind: true | |
| requires-secret: false | |
| # Windows tests | |
| - label: provider | |
| runner: windows-latest | |
| free-disk-space: false | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-docker-wsl | |
| runner: windows-latest | |
| free-disk-space: false | |
| install-kind: true | |
| requires-secret: false | |
| - label: up-features | |
| runner: windows-latest | |
| free-disk-space: false | |
| install-kind: true | |
| requires-secret: false | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 | |
| if: matrix.free-disk-space == true && runner.os == 'Linux' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| - name: install gnupg2 | |
| if: runner.os == 'Linux' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| run: sudo apt-get install -y gnupg2 | |
| - name: get operating system lowercase | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| id: os | |
| shell: bash | |
| run: | | |
| OS=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]') | |
| if [ "$OS" == "macos" ]; then | |
| OS="darwin" | |
| fi | |
| echo "runner_os=$OS" >> "$GITHUB_OUTPUT" | |
| - name: download CLI artifacts | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: devsy-${{ steps.os.outputs.runner_os }} | |
| path: ${{ runner.temp }}/devsy-bin/ | |
| merge-multiple: true | |
| - name: download Linux CLI artifacts for Windows | |
| if: runner.os == 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| pattern: devsy-linux | |
| path: ${{ runner.temp }}/devsy-bin/ | |
| merge-multiple: true | |
| - name: download e2e test binary | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: e2e-test-${{ steps.os.outputs.runner_os }} | |
| path: ./e2e/ | |
| # e2e expects executable to have name defined in e2e/framework/framework.go | |
| - name: setup executable | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| shell: bash | |
| working-directory: ./e2e | |
| run: | | |
| TEMP_DIR="${{ runner.temp }}" | |
| if [ "${{ runner.os }}" == "Windows" ]; then | |
| TEMP_DIR="${TEMP_DIR//\\//}" | |
| fi | |
| ls -R "$TEMP_DIR/devsy-bin/" | |
| mkdir -p ./bin/ | |
| find "$TEMP_DIR/devsy-bin/" -type f -name "devsy-*" -exec cp {} ./bin \; | |
| find ./bin -name "devsy-*" -exec chmod +x {} \; | |
| if [ "${{ runner.os }}" == "Linux" ]; then | |
| chmod +x ./e2e.test | |
| fi | |
| ls -R ./bin/ | |
| - name: generate uuid | |
| if: matrix.install-kind == true && runner.os != 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| id: uuid | |
| shell: bash | |
| run: | | |
| UUID=$(python -c "import uuid; print(uuid.uuid4().hex)") | |
| echo "result=$UUID" >> "$GITHUB_OUTPUT" | |
| - name: cache podman installer (Windows) | |
| if: matrix.install-kind == true && runner.os == 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| id: podman-cache-windows | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ${{ runner.temp }}/podman.msi | |
| key: ${{ runner.os }}-${{ runner.arch }}-podman-v5.8.2 | |
| - name: install and start podman (Windows) | |
| if: matrix.install-kind == true && runner.os == 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| shell: pwsh | |
| run: | | |
| $msiPath = "$env:RUNNER_TEMP\podman.msi" | |
| if ("${{ steps.podman-cache-windows.outputs.cache-hit }}" -ne "true") { | |
| $msiUrl = "https://github.com/containers/podman/releases/download/v5.8.2/podman-installer-windows-amd64.msi" | |
| Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath | |
| } | |
| $expectedHash = "eda54f26f9695d198d9a679fa45ae24ba35b78444f432b5fe0c122c5a3624c57" | |
| $actualHash = (Get-FileHash -Path $msiPath -Algorithm SHA256).Hash.ToLower() | |
| if ($actualHash -ne $expectedHash) { | |
| throw "SHA256 mismatch for podman MSI! Expected: $expectedHash, Got: $actualHash" | |
| } | |
| Write-Host "Podman MSI checksum verified: $actualHash" | |
| $installDir = "C:\Program Files\RedHat\Podman" | |
| $logFile = "$env:RUNNER_TEMP\podman-install.log" | |
| $proc = Start-Process msiexec.exe -Wait -PassThru -ArgumentList "/i `"$msiPath`" /qn /norestart /l*v `"$logFile`" INSTALLDIR=`"$installDir`"" | |
| Write-Host "MSI exit code: $($proc.ExitCode)" | |
| if (!(Test-Path "$installDir\podman.exe")) { | |
| Write-Host "--- MSI install log (last 50 lines) ---" | |
| Get-Content $logFile -Tail 50 | |
| Write-Host "--- Searching for podman.exe ---" | |
| Get-ChildItem "C:\" -Filter "podman.exe" -Recurse -Depth 4 -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_.FullName } | |
| throw "podman.exe not found at $installDir" | |
| } | |
| echo "$installDir" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 | |
| wsl --set-default-version 2 | |
| & "$installDir\podman.exe" machine init | |
| & "$installDir\podman.exe" machine set --rootful | |
| & "$installDir\podman.exe" machine start | |
| - name: cache kind.exe (Windows) | |
| if: matrix.install-kind == true && runner.os == 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| id: kind-cache-windows | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ${{ runner.temp }}/kind.exe | |
| key: ${{ runner.os }}-${{ runner.arch }}-kind-v0.24.0 | |
| - name: setup kind (Windows) | |
| if: matrix.install-kind == true && runner.os == 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| shell: bash | |
| env: | |
| KIND_EXPERIMENTAL_PROVIDER: podman | |
| DOCKER_HOST: npipe:////./pipe/podman-machine-default | |
| run: | | |
| if [ "${{ steps.kind-cache-windows.outputs.cache-hit }}" != "true" ]; then | |
| curl -Lo "$RUNNER_TEMP/kind.exe" "https://github.com/kubernetes-sigs/kind/releases/download/v0.24.0/kind-windows-amd64" | |
| expected="6f724188289cc79395f45afae0f2b85e0d220c2b84c6ed2f5047d9d0c9a67028" | |
| actual=$(sha256sum "$RUNNER_TEMP/kind.exe" | awk '{print $1}' | sed 's/^[^a-f0-9]*//') | |
| if [ "$actual" != "$expected" ]; then | |
| echo "SHA256 mismatch for kind.exe! Expected: $expected, Got: $actual" | |
| exit 1 | |
| fi | |
| echo "kind.exe checksum verified: $actual" | |
| fi | |
| export PATH="$RUNNER_TEMP:$PATH" | |
| echo "$RUNNER_TEMP" >> "$GITHUB_PATH" | |
| CLUSTER_NAME=$(python -c "import uuid; print(uuid.uuid4().hex)") | |
| kind create cluster --name "$CLUSTER_NAME" --image kindest/node:v1.34.0@sha256:7416a61b42b1662ca6ca89f02028ac133a309a2a30ba309614e8ec94d976dc5a | |
| # NOTE: skevetter/setup-kind does not work on Windows runners | |
| - name: setup kind | |
| if: matrix.install-kind == true && runner.os != 'Windows' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| uses: skevetter/setup-kind@7febac2ed35df332069b3bb687c6b1fa00fc0883 # v1 | |
| with: | |
| name: ${{ steps.uuid.outputs.result }} | |
| version: v0.24.0 | |
| image: kindest/node:v1.34.0@sha256:7416a61b42b1662ca6ca89f02028ac133a309a2a30ba309614e8ec94d976dc5a | |
| skipClusterLogsExport: true | |
| - name: cache apt packages (podman/runc) | |
| if: (matrix.install-podman == 'rootless' || matrix.install-podman == 'rootful') && runner.os == 'Linux' | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ${{ runner.temp }}/apt-archives | |
| key: apt-podman-runc-${{ runner.os }}-v1 | |
| - name: Install Podman (Linux rootless) | |
| if: matrix.install-podman == 'rootless' && runner.os == 'Linux' | |
| env: | |
| APT_CACHE_DIR: ${{ runner.temp }}/apt-archives | |
| run: | | |
| # Cache into a runner-owned dir: /var/cache/apt/archives is root-owned | |
| # and actions/cache (running unprivileged) can't write into it on restore. | |
| mkdir -p "$APT_CACHE_DIR" | |
| sudo apt-get -o Dir::Cache::Archives="$APT_CACHE_DIR" update | |
| sudo apt-get -o Dir::Cache::Archives="$APT_CACHE_DIR" install -y podman runc | |
| # podman defaults to crun, which has been observed to fail with | |
| # "OCI runtime error: crun: unknown version specified" on this | |
| # runner image. Force runc, which is known-good, and fail fast | |
| # with diagnostics if it isn't. | |
| mkdir -p ~/.config/containers | |
| printf '[engine]\nruntime = "runc"\n' > ~/.config/containers/containers.conf | |
| podman info | |
| podman run --rm busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d echo "podman runtime preflight OK" | |
| - name: Install Podman (Linux rootful) | |
| if: matrix.install-podman == 'rootful' && runner.os == 'Linux' | |
| env: | |
| APT_CACHE_DIR: ${{ runner.temp }}/apt-archives | |
| run: | | |
| # Cache into a runner-owned dir: /var/cache/apt/archives is root-owned | |
| # and actions/cache (running unprivileged) can't write into it on restore. | |
| mkdir -p "$APT_CACHE_DIR" | |
| sudo apt-get -o Dir::Cache::Archives="$APT_CACHE_DIR" update | |
| sudo apt-get -o Dir::Cache::Archives="$APT_CACHE_DIR" install -y podman runc | |
| # See the rootless step above: force runc over the default crun, | |
| # which has been observed to fail on this runner image. | |
| sudo mkdir -p /etc/containers | |
| printf '[engine]\nruntime = "runc"\n' | sudo tee /etc/containers/containers.conf | |
| sudo systemctl enable --now podman.socket | |
| if ! timeout 30 bash -c 'until sudo podman info >/dev/null 2>&1; do sleep 1; done'; then | |
| echo "::error::podman.socket did not become ready within 30s" | |
| sudo systemctl status podman.socket --no-pager || true | |
| sudo journalctl -u podman.socket --no-pager -n 100 || true | |
| exit 1 | |
| fi | |
| echo "DOCKER_HOST=unix:///run/podman/podman.sock" >> "$GITHUB_ENV" | |
| sudo podman info | |
| sudo podman run --rm busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d echo "podman runtime preflight OK" | |
| - name: get microsandbox latest version | |
| if: matrix.install-microsandbox == true && runner.os == 'Linux' | |
| id: msb-version | |
| run: | | |
| version=$(curl -fsSL https://api.github.com/repos/superradcompany/microsandbox/releases/latest | grep '"tag_name"' | head -1 | sed 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/') | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: cache microsandbox (Linux) | |
| if: matrix.install-microsandbox == true && runner.os == 'Linux' | |
| id: msb-cache | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: | | |
| ~/.microsandbox | |
| ~/.local/bin/msb | |
| ~/.local/bin/microsandbox | |
| key: ${{ runner.os }}-${{ runner.arch }}-microsandbox-${{ steps.msb-version.outputs.version }} | |
| - name: Install microsandbox (Linux) | |
| if: matrix.install-microsandbox == true && runner.os == 'Linux' && steps.msb-cache.outputs.cache-hit != 'true' | |
| run: | | |
| curl -fsSL https://install.microsandbox.dev | sh | |
| - name: configure microsandbox (Linux) | |
| if: matrix.install-microsandbox == true && runner.os == 'Linux' | |
| run: | | |
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | |
| # The e2e test skips gracefully if KVM is unavailable on the runner. | |
| "$HOME/.local/bin/msb" doctor || true | |
| - name: remove docker | |
| if: matrix.label == 'docker-install' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| run: | | |
| sudo systemctl stop docker.socket docker.service | |
| sudo apt-get remove -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | |
| sudo rm -rf /var/lib/docker /var/lib/containerd /usr/bin/docker /usr/bin/dockerd | |
| # The snapshot e2e suite pushes/pulls against a local registry:2 | |
| # fixture at host.docker.internal:15500 (see e2e/tests/snapshot/helper.go), | |
| # reachable both from the host CLI and from inside the workspace | |
| # container. Plain-HTTP is only safe here because that address is | |
| # always local to this runner. | |
| # | |
| # host.docker.internal is Docker Desktop/OrbStack magic; plain Linux | |
| # (this runner) resolves it for neither the host CLI process nor | |
| # containers by default. The container side gets it via the fixture | |
| # devcontainer.json's "--add-host=host.docker.internal:host-gateway" | |
| # runArgs; the host side (the devsy CLI's own push-permission checks, | |
| # which run before any container exists) needs an explicit /etc/hosts | |
| # entry, since there's no running container to attach a gateway to yet. | |
| - name: configure insecure registry for snapshot tests (Linux) | |
| if: matrix.configure-insecure-registry == true && runner.os == 'Linux' | |
| run: | | |
| echo "127.0.0.1 host.docker.internal" | sudo tee -a /etc/hosts | |
| sudo mkdir -p /etc/docker | |
| existing="$(sudo cat /etc/docker/daemon.json 2>/dev/null || echo '{}')" | |
| echo "$existing" | jq '.["insecure-registries"] = ((.["insecure-registries"] // []) + ["host.docker.internal:15500"] | unique)' \ | |
| | sudo tee /etc/docker/daemon.json > /dev/null | |
| sudo systemctl restart docker | |
| timeout 30 bash -c 'until docker info >/dev/null 2>&1; do sleep 1; done' | |
| - name: generate GitHub App token | |
| if: matrix.requires-secret == true && needs.can-read-secret.outputs.secret-set == 'true' | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 | |
| with: | |
| app-id: ${{ secrets.DEVSY_GITHUB_APP_ID }} | |
| private-key: ${{ secrets.DEVSY_GITHUB_APP_PRIVATE_KEY }} | |
| owner: ${{ github.repository_owner }} | |
| - name: run test | |
| if: matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true' | |
| shell: bash | |
| working-directory: ./e2e | |
| env: | |
| # NOTE: GitHub credentials are required for tests using private repos | |
| GH_USERNAME: ${{ github.repository_owner }} | |
| GH_ACCESS_TOKEN: ${{ steps.app-token.outputs.token || github.token }} | |
| GH_CREDENTIAL_USERNAME: x-access-token | |
| run: | | |
| if [ "${{ runner.os }}" == "Linux" ]; then | |
| sudo \ | |
| GH_USERNAME="${GH_USERNAME}" \ | |
| GH_ACCESS_TOKEN="${GH_ACCESS_TOKEN}" \ | |
| GH_CREDENTIAL_USERNAME="${GH_CREDENTIAL_USERNAME}" \ | |
| KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config}" \ | |
| ${DOCKER_HOST:+DOCKER_HOST="${DOCKER_HOST}"} \ | |
| PATH="${PATH}" \ | |
| ./e2e.test -test.v -ginkgo.v -test.timeout 1500s --ginkgo.label-filter="${{ matrix.label }}" | |
| else | |
| GH_USERNAME="${GH_USERNAME}" \ | |
| GH_ACCESS_TOKEN="${GH_ACCESS_TOKEN}" \ | |
| GH_CREDENTIAL_USERNAME="${GH_CREDENTIAL_USERNAME}" \ | |
| KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config}" \ | |
| PATH="${PATH}" \ | |
| DOCKER_HOST="npipe:////./pipe/podman-machine-default" \ | |
| ./e2e.test.exe -test.v -ginkgo.v -test.timeout 1500s --ginkgo.label-filter="${{ matrix.label }}" | |
| fi | |
| - name: verify docker is installed | |
| if: matrix.label == 'docker-install' && (matrix.requires-secret == false || needs.can-read-secret.outputs.secret-set == 'true') | |
| run: docker --version && docker ps | |
| ci-success: | |
| name: CI Success | |
| runs-on: ubuntu-latest | |
| if: always() | |
| needs: | |
| - changes | |
| - precommit | |
| - lint | |
| - licenses | |
| - build-cli | |
| - integration-tests-unprivileged | |
| - integration-tests | |
| steps: | |
| - name: Check required jobs | |
| run: | | |
| # Fail if any required job failed (not skipped) | |
| if [[ "${{ needs.changes.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.precommit.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.lint.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.licenses.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.build-cli.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.integration-tests-unprivileged.result }}" == "failure" ]] || \ | |
| [[ "${{ needs.integration-tests.result }}" == "failure" ]]; then | |
| echo "One or more required jobs failed" | |
| exit 1 | |
| fi | |
| echo "All required jobs passed or were skipped" |