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
6 changes: 3 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# NOTE: tests/ is deliberately kept in the context: the Windows runner image
# (tests/e2e/windows/Dockerfile-runner) is built from the repo root, and both
# Windows Dockerfiles live under tests/.
# NOTE: tests/ is deliberately kept in the context: the Windows image
# (tests/e2e/windows/Dockerfile) is built from the repo root, and its
# Dockerfile lives under tests/.
.git
.gitignore
.gitattributes
Expand Down
36 changes: 19 additions & 17 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ concurrency:
# The Linux and WSL jobs run the suite natively, the way the dev container
# runs it locally: Go at the dev container's version (.devcontainer/Dockerfile)
# plus the runner's stock Docker, with the same TESTCONTAINERS_RYUK_DISABLED
# knob. The Windows jobs keep the compose runner image
# (tests/e2e/windows/Dockerfile-runner), which carries its own Go toolchain,
# so a Windows host needs only Docker. See docs/e2e.md.
# knob. The Windows jobs run tests/e2e/windows/run.ps1, which fetches its own
# pinned Go and tools into a cache dir, so a Windows host needs only Docker.
# See docs/e2e.md.

jobs:
e2e-linux:
Expand Down Expand Up @@ -93,33 +93,35 @@ jobs:
matrix:
# TODO See https://github.com/actions/runner-images/issues/13729
runs-on: [windows-latest, windows-11-arm]
include:
- runs-on: windows-latest
compose: tests/e2e/windows/compose.amd64.yaml
- runs-on: windows-11-arm
compose: tests/e2e/windows/compose.arm64.yaml
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 60
env:
# Run every combo at once (amd64 has three, arm64 two) instead of the
# local default of 2, so the slowest combo alone bounds the test phase
# rather than a queued one running after it (see docs/e2e.md).
E2E_MAX_JOBS: "3"
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
# The windows-11-arm runner ships neither Docker for Windows containers
# nor a Go new enough to build moby, so both are provisioned here.
# The windows-11-arm runner ships no Docker for Windows containers, so
# the engine is built from source (no arm64 binaries are published).
# The build is cached on the script that pins it; a hit skips both the
# Go install and the build.
- if: matrix.runs-on == 'windows-11-arm'
id: docker-arm64
uses: actions/cache@v6
with:
path: C:\vfox-docker\bin
key: docker-windows-arm64-${{ hashFiles('tests/e2e/windows/install-docker-arm64.ps1') }}
- if: matrix.runs-on == 'windows-11-arm' && steps.docker-arm64.outputs.cache-hit != 'true'
uses: actions/setup-go@v6
with:
go-version: 1.27.1
cache: false
- if: matrix.runs-on == 'windows-11-arm'
run: pwsh -NoProfile -File tests/e2e/windows/install-docker-arm64.ps1
- if: matrix.runs-on == 'windows-11-arm'
name: Install Compose CLI plugin
run: |
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.docker\cli-plugins" | Out-Null
curl.exe -fsSL "https://github.com/docker/compose/releases/download/v5.5.1/docker-compose-windows-aarch64.exe" -o "$env:USERPROFILE\.docker\cli-plugins\docker-compose.exe"
docker compose version
- run: docker compose -f ${{ matrix.compose }} run --rm --build e2e
- run: pwsh -NoProfile -File tests/e2e/windows/run.ps1

e2e-wsl:
if: github.repository == 'version-fox/vfox-nodejs'
Expand Down
4 changes: 2 additions & 2 deletions .licenserc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
# Dockerfiles, ignore files and similar text formats are covered.
# Some headers stay hand-written because `header fix` cannot place them:
# go.mod, .gitattributes and .dockerignore have no comment style upstream,
# the Windows Dockerfiles must keep `# escape=` on line 1 (their headers sit
# the Windows Dockerfile must keep `# escape=` on line 1 (its header sits
# right below it), and the fixer only recognises the exact name `Dockerfile`,
# not Dockerfile-runner. The checker still verifies them all.
# not Dockerfile-alpine. The checker still verifies them all.
# PowerShell is check-only here (no `<# ... #>` fix support upstream):
# tests/e2e/windows/*.ps1 is fixed and checked with addlicense instead (see
# the addlicense step in .github/workflows/license.yml and docs/e2e.md).
Expand Down
65 changes: 37 additions & 28 deletions docs/e2e.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ workflow. The end-to-end suite runs in containers against real vfox on Linux
and Windows; each `vfox` x `mirror` combination gets its own throwaway
container. On Linux, CI runs the suite natively on the stock runners (Docker
plus Go from `actions/setup-go`), the way the repository dev container
reproduces it locally. On Windows it runs through a Docker Compose runner
image, since dev containers cannot host Windows container images (see below).
reproduces it locally. On Windows it runs from the host through
`tests/e2e/windows/run.ps1`, since dev containers cannot host Windows
container images (see below).

## Dev container

Expand Down Expand Up @@ -58,7 +59,8 @@ Every combination runs the same flow (one long-lived container per combo,
driven from Go through `docker exec`-style calls):

1. vfox is installed from the requested channel — the latest release
(`latest`) or built from source with the in-image Go toolchain (`main`) —
(`latest`) or built from source with the pinned Go (`main`; inside the
container on Linux, once per run on the host by `run.ps1` on Windows) —
and the local `nodejs` plugin is registered from this checkout.
2. `$VFOX_NODEJS_MIRROR` is honoured positively and negatively: the
configured mirror serves the version index, while a bogus mirror makes
Expand Down Expand Up @@ -155,12 +157,24 @@ Windows containers cannot be emulated across architectures, so the ARM64
suite needs an ARM64 host (a Copilot+ PC or the `windows-11-arm` CI runner).

There is no dev container for this suite — the Dev Containers spec rejects
Windows container images (see [Dev container](#dev-container)) — so it keeps
its Docker Compose runner. The runner image (`Dockerfile-runner`: stock
servercore plus the pinned Go MSI) drives the host daemon through the mounted
named pipe; the host requirement is Docker in Windows-container mode plus the
Compose v5 plugin (installed once per machine below). Go never touches the
host, so it cannot conflict with a vfox-managed toolchain.
Windows container images (see [Dev container](#dev-container)) — so it runs
from the Windows host through `tests/e2e/windows/run.ps1`. The host
requirement is Docker in Windows-container mode; the script needs nothing
beyond the `curl.exe` and `tar.exe` that ship with Windows. It fetches the
pinned PowerShell, PortableGit (Git for Windows, including Git Bash) and Go
into a per-arch cache (`$env:E2E_CACHE_DIR`, default
`%LOCALAPPDATA%\vfox-nodejs-e2e\<arch>`, reused across runs), builds
`vfox@main` once with that Go, compiles the suite, and runs it. None of it is
installed or put on the user `PATH`, so it cannot conflict with a
vfox-managed toolchain.

The cached tools are bind-mounted read-only at `C:\tools` into every combo
container, so `tests/e2e/windows/Dockerfile` only adds `PATH` entries and the
plugin files to stock servercore. Baking the tools into an image layer
instead costs minutes of layer commit on the hosted runners (they are tens of
thousands of files). The servercore pull — five to seven minutes on a fresh
CI runner — runs in the background while the tools are fetched and the Go
code is compiled.

The `windows-11-arm` runner has no Windows Hypervisor Platform feature, so
Hyper-V isolation is unavailable; process isolation needs only the
Expand Down Expand Up @@ -203,15 +217,9 @@ curl.exe -fsSL `
3. Execute in PowerShell 7,

```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.docker\cli-plugins" | Out-Null

curl.exe -fsSL `
"https://github.com/docker/compose/releases/download/v5.5.1/docker-compose-windows-x86_64.exe" `
-o "$env:USERPROFILE\.docker\cli-plugins\docker-compose.exe"

git clone git@github.com:version-fox/vfox-nodejs.git
cd ./vfox-nodejs/
docker compose -f tests/e2e/windows/compose.amd64.yaml run --rm --build e2e
pwsh -NoProfile -File tests/e2e/windows/run.ps1
```

### arm64
Expand All @@ -233,20 +241,21 @@ winget install --id GoLang.Go --source winget --exact
git clone git@github.com:version-fox/vfox-nodejs.git
cd ./vfox-nodejs/
pwsh -NoProfile -File .\tests\e2e\windows\install-docker-arm64.ps1
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.docker\cli-plugins" | Out-Null

curl.exe -fsSL `
"https://github.com/docker/compose/releases/download/v5.5.1/docker-compose-windows-aarch64.exe" `
-o "$env:USERPROFILE\.docker\cli-plugins\docker-compose.exe"

docker compose -f tests/e2e/windows/compose.arm64.yaml run --rm --build e2e
pwsh -NoProfile -File .\tests\e2e\windows\run.ps1
```

On arm64, Go is also what builds the engine, so `install-docker-arm64.ps1`
runs before the suite; the compose runner image then carries its own pinned
Go for the tests, and the host Go is not used again. Scope the run down with
`$env:VFOX_VERSION = 'latest'; $env:MIRROR = 'default'` in front of the
compose command, as on the other platforms.
On arm64, a host Go is needed only to build the engine
(`install-docker-arm64.ps1`); `run.ps1` uses its own cached Go for the suite.
The script reuses an earlier build left in `C:\vfox-docker\bin`; CI restores
that directory with `actions/cache`, keyed on the script, so a cache hit
skips both `actions/setup-go` and the build.

`$env:E2E_RUN` narrows the `-test.run` pattern (default `TestE2E`), e.g.
`TestE2E/latest-default`. Scope the run down with
`$env:VFOX_VERSION = 'latest'; $env:MIRROR = 'default'` in front of it, as on
the other platforms; without `main` in `VFOX_VERSION` the script skips the
`vfox@main` build. CI sets `E2E_MAX_JOBS=3` on both Windows jobs so every
combo runs at once; the local default stays at 2.

## WSL

Expand Down
5 changes: 2 additions & 3 deletions tests/e2e/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
// defaults, retry counts, name handling);
// - linux: the Linux container suite (bash-driven), run in CI and locally
// through the repository dev container (.devcontainer/, see docs/e2e.md);
// - windows: the Windows container suite (pwsh-driven), run via
// tests/e2e/windows/compose.amd64.yaml (amd64) or
// tests/e2e/windows/compose.arm64.yaml (arm64).
// - windows: the Windows container suite (pwsh-driven), run on a Windows
// host via tests/e2e/windows/run.ps1.
// - wsl: the WSL suite (bash-driven through wsl.exe, no containers),
// run on a windows-2025 host with an installed distro; it reproduces
// https://github.com/version-fox/vfox-nodejs/issues/32.
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go 1.25.0
require (
github.com/cenkalti/backoff/v7 v7.0.1
github.com/containerd/platforms v0.2.1
github.com/moby/moby/api v1.55.0
github.com/moby/moby/client v0.5.0
github.com/opencontainers/image-spec v1.1.1
github.com/stretchr/testify v1.12.1
Expand Down Expand Up @@ -49,7 +50,6 @@ require (
github.com/magiconair/properties v1.8.10 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/moby/api v1.55.0 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/sys/sequential v0.7.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
Expand Down
16 changes: 13 additions & 3 deletions tests/e2e/windows/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Per-combo image for the Windows container E2E suite, built by e2e_test.go.
# pwsh, Git for Windows and vfox@main are not baked in: run.ps1 fetches them
# on the host and the suite bind-mounts them read-only at C:\tools, because
# committing an image layer with their tens of thousands of files takes
# minutes on the hosted runners. This image only points PATH at the mount
# and adds the plugin files.
ARG BASE_IMAGE=mcr.microsoft.com/windows/servercore:ltsc2025-KB5122871-amd64
FROM ${BASE_IMAGE}

SHELL ["powershell", "-NoProfile", "-Command"]

COPY tests/e2e/windows/bootstrap-tools.ps1 C:\bootstrap-tools.ps1
RUN powershell -NoProfile -ExecutionPolicy Bypass -File 'C:\bootstrap-tools.ps1'
# NB: no double quotes or backticks inside the command. The classic builder
# wraps it in powershell -Command "..." through cmd.exe, where both break
# parsing. Single quotes only.
RUN [Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'Machine') + ';C:\tools\pwsh;C:\tools\git\cmd', 'Machine'); `
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1 -PropertyType DWORD -Force | Out-Null

WORKDIR C:\e2e

Expand All @@ -28,5 +38,5 @@ COPY lib C:\e2e\lib

# Long-lived container: the Go test (e2e_test.go) drives every phase through
# pwsh exec calls, so the main process just idles here.
ENTRYPOINT ["C:/Program Files/PowerShell/7/pwsh.exe", "-NoProfile", "-Command"]
ENTRYPOINT ["C:/tools/pwsh/pwsh.exe", "-NoProfile", "-Command"]
CMD ["while ($true) { Start-Sleep 3600 }"]
40 changes: 0 additions & 40 deletions tests/e2e/windows/Dockerfile-runner

This file was deleted.

53 changes: 0 additions & 53 deletions tests/e2e/windows/bootstrap-tools.ps1

This file was deleted.

Loading
Loading