Skip to content

Commit 8c7dad2

Browse files
authored
Fix 32-bit arch resolution (386/arm), correct Windows source-build claim, add multi-arch CI (#7)
* fix(arch): handle vfox/mise 32-bit values (386, arm); mark Windows source-build unsupported normalize_arch missed Go-GOARCH "386" (vfox 32-bit x86) and "arm" (vfox+mise 32-bit ARM), so x32 and ARMv7 installs failed to resolve. Map 386->i686 and arm->armv7, with tests using the real values vfox/mise emit. Also correct the README table: Windows source builds are unsupported (the Windows note already says so), so the Source Build column for the Windows rows is now marked absent. * ci: add binary-only multi-arch e2e (Linux aarch64/armv7 via QEMU, macOS x64) New arch-e2e.yml runs real prebuilt-binary Nim installs on emulated Linux aarch64 and armv7 (vfox under run-on-arch, exercising the GOARCH arm/arm64 values and the normalize_arch fix) and on macOS x64 (macos-15-intel via mise). Binary-only (VFOX_NIM_INSTALL_METHOD=binary, nim@ref:devel nightly binaries) so nothing compiles under emulation. Kept off the per-PR path: push-to-main, manual dispatch, and a weekly cron only. * TEMP: trigger arch-e2e on x32-arch-and-ci branch for validation * ci(arch-e2e): fix vfox tarball extraction path and use mise plugin link * ci(arch-e2e): vfox add needs a zip — build via git archive HEAD * ci(arch-e2e): vfox installs ref:devel as version 'devel' — use/activate that * ci(arch-e2e): activate nim via project .tool-versions (vfox use -g is no-op non-interactively) * ci(arch-e2e): remove temporary branch trigger (validation complete) * docs(changelog): document the rest of v0.1.1 (386/arm fix, multi-arch CI, docs, community) --------- Co-authored-by: elijahr <153711+elijahr@users.noreply.github.com>
1 parent f96abb5 commit 8c7dad2

6 files changed

Lines changed: 212 additions & 4 deletions

File tree

.github/actionlint.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# macos-15-intel is a real GitHub-hosted Intel runner (macos-13 was retired
2+
# 2025-12-04; macos-latest is arm64). The pinned actionlint pre-commit hook
3+
# predates this label, so declare it here — actionlint auto-discovers this file
4+
# and will then accept it. Standalone/newer actionlint already knows it.
5+
self-hosted-runner:
6+
labels:
7+
- macos-15-intel

.github/workflows/arch-e2e.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# yamllint disable rule:line-length
2+
3+
name: Arch e2e
4+
5+
# These are SLOW end-to-end legs (QEMU emulation + an Intel macOS runner), so they
6+
# are kept OFF the per-PR path. They run on push-to-main, manual dispatch, and a
7+
# weekly cron only. Every install here is binary-only (VFOX_NIM_INSTALL_METHOD=binary
8+
# + nim@ref:devel prebuilt nightlies) so nothing compiles from source under emulation
9+
# or on the extra runner.
10+
11+
# yamllint disable rule:truthy
12+
on:
13+
# yamllint enable rule:truthy
14+
workflow_dispatch: {}
15+
push:
16+
branches: [main]
17+
paths:
18+
- hooks/**
19+
- metadata.lua
20+
- .github/workflows/arch-e2e.yml
21+
schedule:
22+
# Weekly, Monday 06:00 UTC.
23+
- cron: "0 6 * * 1"
24+
25+
permissions:
26+
contents: read
27+
28+
jobs:
29+
# Emulated Linux aarch64 + armv7 via QEMU (uraimo/run-on-arch-action). Exercises
30+
# the GOARCH arm/arm64 values and the normalize_arch fix against real prebuilt
31+
# binaries through vfox. Binary-only: ref:devel resolves to the generic nightly
32+
# binaries (aarch64 -> linux_arm64.tar.xz, armv7 -> linux_armv7l.tar.xz) and
33+
# VFOX_NIM_INSTALL_METHOD=binary turns a missing binary into a hard error rather
34+
# than a source compile.
35+
linux_multiarch_e2e:
36+
name: Linux ${{ matrix.arch }} e2e
37+
runs-on: ubuntu-latest
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
include:
42+
- arch: aarch64
43+
distro: ubuntu22.04
44+
vfox_asset: vfox_1.0.11_linux_aarch64.tar.gz
45+
- arch: armv7
46+
distro: ubuntu22.04
47+
vfox_asset: vfox_1.0.11_linux_armv7.tar.gz
48+
steps:
49+
- name: Checkout plugin
50+
uses: actions/checkout@v4
51+
with:
52+
fetch-depth: 0
53+
54+
- name: Binary-only Nim install under emulation
55+
uses: uraimo/run-on-arch-action@v2
56+
with:
57+
arch: ${{ matrix.arch }}
58+
distro: ${{ matrix.distro }}
59+
githubToken: ${{ secrets.GITHUB_TOKEN }}
60+
# Mount the checkout at a fixed path so the plugin source has a
61+
# deterministic location inside the container (independent of the
62+
# host workspace path).
63+
dockerRunArgs: |
64+
--volume "${{ github.workspace }}:/plugin"
65+
env: |
66+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
67+
VFOX_NIM_INSTALL_METHOD: binary
68+
install: |
69+
apt-get update
70+
apt-get install -y curl xz-utils ca-certificates git
71+
run: |
72+
set -euo pipefail
73+
74+
# Install vfox from the release tarball for this arch.
75+
curl -fsSL -o /tmp/vfox.tar.gz \
76+
"https://github.com/version-fox/vfox/releases/download/v1.0.11/${{ matrix.vfox_asset }}"
77+
tar -xzf /tmp/vfox.tar.gz -C /tmp
78+
mv "/tmp/vfox_1.0.11_linux_${{ matrix.arch }}/vfox" /usr/local/bin/vfox
79+
chmod +x /usr/local/bin/vfox
80+
vfox --version
81+
82+
# Sandbox vfox state under HOME (VFOX_HOME is vfox's documented home
83+
# override, the same var the integration spec sets).
84+
export VFOX_HOME="$HOME/.version-fox"
85+
mkdir -p "$VFOX_HOME"
86+
87+
# vfox add --source needs a .zip/.lua, not a directory. Build a zip of
88+
# the checkout exactly like the vfox integration spec does (git archive
89+
# of HEAD -> metadata.lua at the zip root), then add it. safe.directory
90+
# is needed because the mounted /plugin is owned by a different uid.
91+
git config --global --add safe.directory /plugin
92+
git -C /plugin archive --format=zip --output=/tmp/nim.zip HEAD
93+
vfox add --source /tmp/nim.zip --alias nim
94+
95+
# Binary-only install (ref:devel registers under the version name "devel").
96+
vfox install -y nim@ref:devel
97+
98+
# `vfox use -g` does NOT take effect in a non-interactive shell (per the
99+
# vfox integration spec), so activate a project-local .tool-versions instead:
100+
# inside a dir declaring `nim devel`, `vfox activate` materializes the sdk
101+
# and prepends its bin to PATH.
102+
mkdir -p /tmp/proj
103+
printf 'nim devel\n' > /tmp/proj/.tool-versions
104+
cd /tmp/proj
105+
eval "$(vfox activate bash)"
106+
nim --version
107+
108+
# macOS x64 via mise. macos-13 (the last Intel image) is retired and
109+
# macos-latest is arm64, so macos-15-intel is the only hosted x64 macOS runner.
110+
# ref:devel resolves to the macosx_x64.tar.xz prebuilt nightly binary.
111+
macos_x64_e2e:
112+
name: macOS x64 e2e
113+
runs-on: macos-15-intel
114+
steps:
115+
- name: Checkout plugin
116+
uses: actions/checkout@v4
117+
with:
118+
fetch-depth: 0
119+
120+
- name: Install mise
121+
uses: jdx/mise-action@v2
122+
with:
123+
install: false
124+
125+
- name: Binary-only Nim install on macOS x64
126+
shell: bash
127+
env:
128+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
129+
MISE_YES: 1
130+
VFOX_NIM_INSTALL_METHOD: binary
131+
run: |
132+
set -euo pipefail
133+
134+
# Register THIS checkout as the `nim` plugin, mirroring the mise
135+
# integration spec's local-plugin registration.
136+
mise plugin link --force nim "$GITHUB_WORKSPACE"
137+
138+
# Binary-only install + activate + run, mirroring the spec's
139+
# install / use / exec forms.
140+
mise install nim@ref:devel
141+
mise use -g nim@ref:devel
142+
mise exec nim@ref:devel -- nim --version

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,36 @@ All notable changes to vfox-nim are documented here. Format follows
1010

1111
_Not yet released — the `v0.1.1` tag and GitHub Release are created by the **Release** workflow (manually dispatched from `main` after this commit lands)._
1212

13+
### Added
14+
15+
- Multi-arch end-to-end CI (`arch-e2e.yml`): binary-only Nim installs on emulated
16+
Linux `aarch64` and `armv7` (vfox under `uraimo/run-on-arch-action`) and on macOS
17+
x64 (`macos-15-intel` via mise). Runs on push-to-main, manual dispatch, and a
18+
weekly cron (kept off the per-PR path).
19+
- README: status badges, an install demo placeholder plus a `console` transcript,
20+
a scannable feature list, a "Installing versions" section (latest / specific /
21+
partial-series / `ref:devel` / branches / commits / `.nim-version` / `GITHUB_TOKEN`),
22+
and a "GitHub Actions" usage guide including the Windows Nim DLL setup.
23+
- Community infrastructure: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`,
24+
bug-report and feature-request issue forms, and a pull-request template.
25+
26+
### Changed
27+
28+
- README platform table: the Windows rows no longer claim source-build support
29+
(the plugin installs prebuilt binaries on Windows and does not build from source
30+
there); the Source Build column is marked unsupported for the Windows rows.
31+
- README now presents vfox-nim explicitly as an independent third-party plugin
32+
installed from this repository under a local plugin name, rather than as a
33+
registry-provided `nim`.
34+
1335
### Fixed
1436

37+
- `normalize_arch` now also handles the 32-bit values vfox/mise actually emit: Go's
38+
`GOARCH` `386` (vfox, 32-bit x86) maps to `i686`, and `arm` (both tools, 32-bit ARM)
39+
maps to `armv7`. Previously only `i386`/`i686`/`x86` and `armv7`/`armv7l` were
40+
matched — values neither tool emits for those targets — so Windows/Linux x32 (under
41+
vfox) and Linux ARMv7 (under both) failed to resolve a binary. Unit tests now assert
42+
the real emitted values through to the resolved asset URLs.
1543
- `normalize_arch` is now OS-aware: it returns `aarch64` for both
1644
`aarch64` and `arm64` input on Linux (matching Nim's nightly +
1745
source tarball naming) and keeps `arm64` on macOS. The prior

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ For platforms without official binaries (macOS, Linux ARM), the plugin uses Nim'
2323
| Linux x32 |||| ~30s |
2424
| Linux ARM64 |||| ~60s |
2525
| Linux ARMv7 |||| ~60s |
26-
| Windows x64 ||| | ~30s |
27-
| Windows x32 ||| | ~30s |
26+
| Windows x64 ||| | ~30s |
27+
| Windows x32 ||| | ~30s |
2828
| macOS x64 |||| ~60s |
2929
| macOS ARM64 |||| ~60s |
3030

hooks/lib/nim_utils.lua

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,23 @@ end
2424
-- spell it `aarch64`. vfox/mise pass Go's `runtime.GOARCH` verbatim, which is
2525
-- `arm64` on Linux/ARM64 hosts too, so the `aarch64`/`arm64` branch below has
2626
-- to pivot on `os_name` to pick the right downstream spelling.
27+
--
28+
-- 32-bit inputs also vary by harness: vfox passes Go's GOARCH verbatim (`386`
29+
-- for 32-bit x86, `arm` for 32-bit ARM), while mise passes Rust's ARCH (`x86`
30+
-- for 32-bit x86, `arm` for 32-bit ARM). Both spellings must map correctly,
31+
-- so the branches below accept `386`/`x86` (-> i686) and `arm` (-> armv7).
2732
function M.normalize_arch(arch, os_name)
2833
arch = arch:lower()
2934
if arch == "x86_64" or arch == "amd64" then
3035
return "x86_64"
31-
elseif arch == "i386" or arch == "i686" or arch == "x86" then
36+
elseif arch == "386" or arch == "i386" or arch == "i686" or arch == "x86" then
3237
return "i686"
3338
elseif arch == "aarch64" or arch == "arm64" then
3439
if os_name == "macos" or os_name == "darwin" then
3540
return "arm64"
3641
end
3742
return "aarch64"
38-
elseif arch == "armv7" or arch == "armv7l" then
43+
elseif arch == "arm" or arch == "armv7" or arch == "armv7l" then
3944
return "armv7"
4045
else
4146
return arch

spec/smoke_spec.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ describe("vfox-nim smoke tests", function()
223223
assert.equal("x86_64", utils.normalize_arch("amd64", "linux"))
224224
assert.equal("x86_64", utils.normalize_arch("x86_64", "linux"))
225225
assert.equal("i686", utils.normalize_arch("x86", "linux"))
226+
-- vfox passes Go's GOARCH ("386" for 32-bit x86, "arm" for 32-bit
227+
-- ARM); mise passes Rust's ARCH ("x86" for 32-bit x86, "arm" for
228+
-- 32-bit ARM). All must normalize to Nim's spellings.
229+
assert.equal("i686", utils.normalize_arch("386", "linux"))
230+
assert.equal("i686", utils.normalize_arch("386", "windows"))
231+
assert.equal("i686", utils.normalize_arch("x86", "linux"))
232+
assert.equal("armv7", utils.normalize_arch("arm", "linux"))
226233
-- 64-bit ARM normalizes to "aarch64" on Linux but "arm64" on
227234
-- macOS, matching Nim's nightly + tarball URL spellings.
228235
assert.equal("aarch64", utils.normalize_arch("arm64", "linux"))
@@ -231,6 +238,25 @@ describe("vfox-nim smoke tests", function()
231238
assert.equal("arm64", utils.normalize_arch("aarch64", "macos"))
232239
end)
233240

241+
it("resolves 32-bit arch values to the right assets", function()
242+
local utils = require("lib.nim_utils")
243+
-- vfox/mise 32-bit values must normalize and then resolve to the
244+
-- correct Nim distribution assets/urls.
245+
assert.equal(
246+
"windows_x32.zip",
247+
utils.get_platform_filename("windows", utils.normalize_arch("386", "windows"))
248+
)
249+
assert.equal(
250+
"https://nim-lang.org/download/nim-2.2.4_x32.zip",
251+
utils.get_official_url("2.2.4", "windows", utils.normalize_arch("386", "windows"))
252+
)
253+
assert.equal("linux_x32.tar.xz", utils.get_platform_filename("linux", utils.normalize_arch("386", "linux")))
254+
assert.equal(
255+
"linux_armv7l.tar.xz",
256+
utils.get_platform_filename("linux", utils.normalize_arch("arm", "linux"))
257+
)
258+
end)
259+
234260
it("detects stable versions", function()
235261
local utils = require("lib.nim_utils")
236262
assert.is_true(utils.is_stable_version("2.2.4"))

0 commit comments

Comments
 (0)