Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 67 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ name: ci
# path: resolve, download, verify against SHA256SUMS, extract, PATH, install the
# engine, wait for it, and run a container through it. The stage-only path
# (install: false) and the GitLab-style script call are covered too.
#
# All of that needs a release to install, and the newest one may still predate
# the Skrog rename (#1) -- every release through v0.3.1 publishes
# hawser_<version>_windows_<arch>.zip, which this action deliberately no longer
# knows how to fetch. The probe below decides: the download jobs run once a
# release carries a skrog-named asset, and are skipped with a reason until then.
# It is not a temporary hack -- "there is nothing published to install" is a
# real state for an installer's CI, and this reports it instead of failing.

on:
push:
Expand All @@ -14,52 +22,95 @@ permissions:
contents: read

jobs:
release-ready:
name: is there a skrog-named release to install?
runs-on: ubuntu-latest
outputs:
ready: ${{ steps.probe.outputs.ready }}
steps:
- id: probe
shell: bash
env:
GH_TOKEN: ${{ github.token }}
# set -e matters: an API or auth failure must fail this job, so a broken
# probe can never quietly skip the whole suite. gh's own --jq is used
# rather than piping to jq, so the same command is runnable anywhere gh
# is -- including a maintainer's laptop, which is how this was checked.
run: |
set -euo pipefail
out=$(gh api 'repos/wslkit/skrog/releases?per_page=50' --jq '
[ .[] | select(.draft | not)
| select(.tag_name | test("^v[0-9]+[.][0-9]+[.][0-9]+$")) ]
| sort_by(.created_at) | reverse | .[0] // empty
| "\(.tag_name) \([.assets[].name | select(startswith("skrog_"))] | length)"')
if [ -z "$out" ]; then
echo "no published app release in wslkit/skrog yet; nothing to install"
echo "ready=false" >> "$GITHUB_OUTPUT"
exit 0
fi
tag=${out% *}
n=${out##* }
if [ "$n" -gt 0 ]; then
echo "newest release $tag ships $n skrog-named asset(s); running the download jobs"
echo "ready=true" >> "$GITHUB_OUTPUT"
else
echo "newest release $tag predates the rename, so it has no skrog_* asset."
echo "Skipping the download jobs until v0.4.0 is published."
echo "ready=false" >> "$GITHUB_OUTPUT"
fi

install-via-action:
name: action installs the engine and docker runs (windows-latest)
needs: release-ready
if: needs.release-ready.outputs.ready == 'true'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- id: hawser
- id: skrog
uses: ./
- name: docker targets the Hawser engine
- name: docker targets the Skrog engine
shell: pwsh
run: |
if ($env:DOCKER_CONTEXT -ne 'hawser') { throw "DOCKER_CONTEXT is '$env:DOCKER_CONTEXT', expected 'hawser'" }
if ("${{ steps.hawser.outputs.docker-context }}" -ne 'hawser') { throw "docker-context output is not 'hawser'" }
if ($env:DOCKER_CONTEXT -ne 'skrog') { throw "DOCKER_CONTEXT is '$env:DOCKER_CONTEXT', expected 'skrog'" }
if ("${{ steps.skrog.outputs.docker-context }}" -ne 'skrog') { throw "docker-context output is not 'skrog'" }
docker version
if ($LASTEXITCODE -ne 0) { throw "docker version failed ($LASTEXITCODE)" }
$name = docker info --format '{{.Name}}'
Write-Host "engine host: $name"
docker run --rm hello-world
if ($LASTEXITCODE -ne 0) { throw "docker run hello-world failed ($LASTEXITCODE)" }
hawser status --json | Out-Host
skrog status --json | Out-Host
exit 0

stage-via-action:
name: install=false only stages hawser.exe
name: install=false only stages skrog.exe
needs: release-ready
if: needs.release-ready.outputs.ready == 'true'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- id: hawser
- id: skrog
uses: ./
with:
install: 'false'
- name: hawser.exe is on PATH and reports its version
- name: skrog.exe is on PATH and reports its version
shell: pwsh
run: |
$out = & hawser version 2>&1 | Out-String
$out = & skrog version 2>&1 | Out-String
$code = $LASTEXITCODE
Write-Host $out
# 3 = no engine installed, which is exactly this runner's state.
if ($code -ne 0 -and $code -ne 3) { throw "hawser version exited $code" }
if (-not "${{ steps.hawser.outputs.version }}") { throw "action reported no version output" }
if ($env:HAWSER_HOME -ne "${{ steps.hawser.outputs.home }}") { throw "HAWSER_HOME and the home output disagree" }
Write-Host "staged hawser ${{ steps.hawser.outputs.version }} at ${{ steps.hawser.outputs.home }}"
if ($code -ne 0 -and $code -ne 3) { throw "skrog version exited $code" }
if (-not "${{ steps.skrog.outputs.version }}") { throw "action reported no version output" }
if ($env:SKROG_HOME -ne "${{ steps.skrog.outputs.home }}") { throw "SKROG_HOME and the home output disagree" }
Write-Host "staged skrog ${{ steps.skrog.outputs.version }} at ${{ steps.skrog.outputs.home }}"
# The step's exit code is the last native command's; don't leak the 3.
exit 0

stage-via-script:
name: script stages hawser.exe (GitLab-style)
name: script stages skrog.exe (GitLab-style)
needs: release-ready
if: needs.release-ready.outputs.ready == 'true'
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -68,9 +119,9 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
pwsh -File scripts/install-hawser.ps1 -Install:$false -Dest "$env:RUNNER_TEMP\hawser-script"
pwsh -File scripts/install-skrog.ps1 -Install:$false -Dest "$env:RUNNER_TEMP\skrog-script"
if ($LASTEXITCODE -ne 0) { throw "script exited $LASTEXITCODE" }
if (-not (Test-Path "$env:RUNNER_TEMP\hawser-script\bin\hawser.exe")) { throw "hawser.exe not staged" }
if (-not (Test-Path "$env:RUNNER_TEMP\skrog-script\bin\skrog.exe")) { throw "skrog.exe not staged" }
exit 0

lint:
Expand Down
62 changes: 31 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
# setup-hawser
# setup-skrog

Install a pinned [Hawser](https://github.com/hawserhq/hawser) — the upstream
Install a pinned [Skrog](https://github.com/wslkit/skrog) — the upstream
open source Docker Engine on Windows via WSL2 — on a Windows runner, verified
against the release's `SHA256SUMS`, and wait for the engine to answer. One line
replaces Docker Desktop on the runner: no per-runner license, no auto-updates
you did not schedule, and the same pinned engine your developers run.

```yaml
- uses: hawserhq/setup-hawser@v1
- uses: wslkit/setup-skrog@v1
with:
version: 0.3.0 # or omit: "latest"
- run: docker run --rm hello-world
```

After the step, `docker` targets the engine (the `hawser` docker context is
After the step, `docker` targets the engine (the `skrog` docker context is
exported as `DOCKER_CONTEXT`), so compose, Testcontainers, Dev Containers and
anything else that follows docker follow it too.

## Laptop == runner: the lockfile

Commit a `hawser.lock` (`hawser lock` writes one) and the action installs
Commit a `skrog.lock` (`skrog lock` writes one) and the action installs
**exactly that engine** — dockerd, containerd, runc, BuildKit to the commit —
while `hawser install --locked hawser.lock` does the same on a laptop. "Works
while `skrog install --locked skrog.lock` does the same on a laptop. "Works
locally, fails in CI" from engine drift stops being a category. The lock is
auto-detected in the working directory, or pointed at with `lockfile:`.

Expand All @@ -31,31 +31,31 @@ Installing the engine needs WSL2. **GitHub-hosted `windows-latest` runners have
it** — this repo's own CI installs the engine and runs `docker run hello-world`
on one — and so does any self-hosted Windows runner with WSL2 enabled. On a
machine without WSL2 the action fails with a clear "WSL2 is not available"
message; use `install: false` there to stage `hawser.exe` on PATH only (useful
for `hawser bundle`, `hawser lock`, packaging steps).
message; use `install: false` there to stage `skrog.exe` on PATH only (useful
for `skrog bundle`, `skrog lock`, packaging steps).

Self-hosted runners also need a logged-on session for WSL2 — see
[auto-logon-runner.md](https://github.com/hawserhq/hawser/blob/main/docs/auto-logon-runner.md);
`hawser runner check` verifies that setup.
[auto-logon-runner.md](https://github.com/wslkit/skrog/blob/main/docs/auto-logon-runner.md);
`skrog runner check` verifies that setup.

## Inputs

| Input | Default | What it does |
| --- | --- | --- |
| `version` | `latest` | Hawser release to install, e.g. `0.3.0` |
| `lockfile` | `` | Path to a `hawser.lock` (auto-detects `./hawser.lock`) |
| `install` | `true` | Install and start the engine; `false` stages `hawser.exe` only |
| `install-args` | `` | Extra `hawser install` arguments |
| `version` | `latest` | Skrog release to install, e.g. `0.3.0` |
| `lockfile` | `` | Path to a `skrog.lock` (auto-detects `./skrog.lock`) |
| `install` | `true` | Install and start the engine; `false` stages `skrog.exe` only |
| `install-args` | `` | Extra `skrog install` arguments |
| `wait` | `3m` | How long to wait for the engine to answer |
| `token` | `${{ github.token }}` | For the release API when resolving `latest` |

## Outputs

| Output | Meaning |
| --- | --- |
| `version` | Installed Hawser version |
| `home` | Directory holding `hawser.exe` (on PATH; also `HAWSER_HOME`) |
| `docker-context` | `hawser` — the docker context targeting the engine |
| `version` | Installed Skrog version |
| `home` | Directory holding `skrog.exe` (on PATH; also `SKROG_HOME`) |
| `docker-context` | `skrog` — the docker context targeting the engine |

## GitLab and other CI

Expand All @@ -64,9 +64,9 @@ runs the same logic. In `.gitlab-ci.yml` on a Windows runner:

```yaml
before_script:
- Invoke-WebRequest https://raw.githubusercontent.com/hawserhq/setup-hawser/v1/scripts/install-hawser.ps1 -OutFile install-hawser.ps1
- pwsh -File install-hawser.ps1 -Version 0.3.0
- $env:DOCKER_CONTEXT = 'hawser'
- Invoke-WebRequest https://raw.githubusercontent.com/wslkit/setup-skrog/v1/scripts/install-skrog.ps1 -OutFile install-skrog.ps1
- pwsh -File install-skrog.ps1 -Version 0.3.0
- $env:DOCKER_CONTEXT = 'skrog'
```

Pin the script by tag, exactly as you would pin the action. The script has the
Expand All @@ -76,29 +76,29 @@ same parameters as the inputs above (`-Version`, `-Lockfile`, `-Install`,
## What the action does, precisely

1. Resolves the release (or uses the pinned version).
2. Downloads `hawser_<version>_windows_<arch>.zip` and `SHA256SUMS` from the
2. Downloads `skrog_<version>_windows_<arch>.zip` and `SHA256SUMS` from the
GitHub release and **refuses on any checksum mismatch**.
3. Extracts, puts `hawser.exe` on `PATH`, exports `HAWSER_HOME`.
3. Extracts, puts `skrog.exe` on `PATH`, exports `SKROG_HOME`.
4. With `install: true`: checks WSL2 is available, runs
`hawser install --headless --no-autostart` (plus `--locked` when a lock is
present and the release supports it), `hawser start`, then waits with
`hawser healthcheck --wait` (or by polling `status --json` on releases that
predate `healthcheck`), and exports `DOCKER_CONTEXT=hawser`.
`skrog install --headless --no-autostart` (plus `--locked` when a lock is
present and the release supports it), `skrog start`, then waits with
`skrog healthcheck --wait` (or by polling `status --json` on releases that
predate `healthcheck`), and exports `DOCKER_CONTEXT=skrog`.

Nothing is fetched as "latest" inside Hawser itself: the release pins its engine
Nothing is fetched as "latest" inside Skrog itself: the release pins its engine
rootfs by SHA-256, and the lockfile pins it to the commit.

## Runners without a docker CLI

`hawser cli install` installs the upstream docker CLI + compose + buildx on the
`skrog cli install` installs the upstream docker CLI + compose + buildx on the
runner (checksum-pinned), if the runner image has none:

```yaml
- uses: hawserhq/setup-hawser@v1
- run: hawser cli install --no-path
- uses: wslkit/setup-skrog@v1
- run: skrog cli install --no-path
```

## License

[Apache-2.0](LICENSE). Hawser is not affiliated with or endorsed by Docker, Inc.;
[Apache-2.0](LICENSE). Skrog is not affiliated with or endorsed by Docker, Inc.;
Docker is a trademark of Docker, Inc.
26 changes: 13 additions & 13 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
name: 'Setup Hawser'
name: 'Setup Skrog'
description: >-
Install a pinned Hawser (upstream Docker Engine on Windows via WSL2) on a
Install a pinned Skrog (upstream Docker Engine on Windows via WSL2) on a
Windows runner, verified against the release's SHA256SUMS, and wait for the
engine to answer. One line replaces Docker Desktop on the runner.
author: 'hawserhq'
author: 'wslkit'
branding:
icon: 'anchor'
color: 'blue'

inputs:
version:
description: 'Hawser release to install (e.g. 0.3.0). "latest" resolves the newest release.'
description: 'Skrog release to install (e.g. 0.3.0). "latest" resolves the newest release.'
required: false
default: 'latest'
lockfile:
description: 'Path to a hawser.lock that pins the engine (install --locked). Empty auto-detects ./hawser.lock.'
description: 'Path to a skrog.lock that pins the engine (install --locked). Empty auto-detects ./skrog.lock.'
required: false
default: ''
install:
description: >-
Run `hawser install` and start the engine (needs WSL2 on the runner;
GitHub-hosted windows-latest has it). "false" only stages hawser.exe
Run `skrog install` and start the engine (needs WSL2 on the runner;
GitHub-hosted windows-latest has it). "false" only stages skrog.exe
on PATH.
required: false
default: 'true'
install-args:
description: 'Extra arguments appended to `hawser install` (e.g. --engine-version 29.8.0).'
description: 'Extra arguments appended to `skrog install` (e.g. --engine-version 29.8.0).'
required: false
default: ''
wait:
Expand All @@ -39,20 +39,20 @@ inputs:

outputs:
version:
description: 'The Hawser version that was installed.'
description: 'The Skrog version that was installed.'
value: ${{ steps.run.outputs.version }}
home:
description: 'Directory holding hawser.exe (also added to PATH and exported as HAWSER_HOME).'
description: 'Directory holding skrog.exe (also added to PATH and exported as SKROG_HOME).'
value: ${{ steps.run.outputs.home }}
docker-context:
description: 'The docker context that targets the engine after install (also exported as DOCKER_CONTEXT).'
value: 'hawser'
value: 'skrog'

runs:
using: 'composite'
steps:
# One script does the work so GitLab and other CI systems run the exact same
# logic (scripts/install-hawser.ps1); the action only maps inputs onto it.
# logic (scripts/install-skrog.ps1); the action only maps inputs onto it.
# Inputs reach the script through env, never spliced into the command line.
- id: run
shell: pwsh
Expand All @@ -65,7 +65,7 @@ runs:
GH_TOKEN: ${{ inputs.token }}
run: |
$install = $env:INPUT_INSTALL -ne 'false'
& "$env:GITHUB_ACTION_PATH/scripts/install-hawser.ps1" `
& "$env:GITHUB_ACTION_PATH/scripts/install-skrog.ps1" `
-Version $env:INPUT_VERSION `
-Lockfile $env:INPUT_LOCKFILE `
-Install $install `
Expand Down
Loading
Loading