Skip to content

Commit 4b2c70d

Browse files
committed
fix(ci): pin Zig 0.15.2 in GitHub Actions
1 parent 126e6b7 commit 4b2c70d

2 files changed

Lines changed: 183 additions & 5 deletions

File tree

.github/scripts/install-zig.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
if [ "$#" -ne 1 ]; then
5+
echo "usage: $0 <zig-version>" >&2
6+
exit 1
7+
fi
8+
9+
version="$1"
10+
11+
python_bin="${PYTHON:-python3}"
12+
if ! command -v "$python_bin" >/dev/null 2>&1; then
13+
python_bin="python"
14+
fi
15+
if ! command -v "$python_bin" >/dev/null 2>&1; then
16+
echo "python is required to install Zig" >&2
17+
exit 1
18+
fi
19+
20+
runner_os="${RUNNER_OS:-$(uname -s)}"
21+
runner_arch="${RUNNER_ARCH:-$(uname -m)}"
22+
23+
case "$runner_os" in
24+
Linux | linux)
25+
zig_os="linux"
26+
;;
27+
Darwin | macOS)
28+
zig_os="macos"
29+
;;
30+
Windows | MINGW* | MSYS* | CYGWIN*)
31+
zig_os="windows"
32+
;;
33+
*)
34+
echo "unsupported runner OS: $runner_os" >&2
35+
exit 1
36+
;;
37+
esac
38+
39+
case "$runner_arch" in
40+
X64 | x86_64 | amd64)
41+
zig_arch="x86_64"
42+
;;
43+
ARM64 | arm64 | aarch64)
44+
zig_arch="aarch64"
45+
;;
46+
*)
47+
echo "unsupported runner architecture: $runner_arch" >&2
48+
exit 1
49+
;;
50+
esac
51+
52+
host_key="${zig_arch}-${zig_os}"
53+
tool_root="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/websocket-zig"
54+
install_dir="${tool_root}/${version}/${host_key}"
55+
zig_bin="zig"
56+
if [ "$zig_os" = "windows" ]; then
57+
zig_bin="zig.exe"
58+
fi
59+
60+
if [ ! -x "${install_dir}/${zig_bin}" ]; then
61+
mkdir -p "$(dirname "$install_dir")"
62+
63+
zig_metadata="$(
64+
"$python_bin" - "$version" "$host_key" <<'PY'
65+
import json
66+
import sys
67+
import urllib.request
68+
69+
version = sys.argv[1]
70+
host_key = sys.argv[2]
71+
72+
with urllib.request.urlopen("https://ziglang.org/download/index.json") as response:
73+
data = json.load(response)
74+
75+
host = data.get(version, {}).get(host_key)
76+
if not host:
77+
raise SystemExit(f"missing Zig download metadata for version={version!r} host={host_key!r}")
78+
79+
archive_url = host.get("tarball") or host.get("zip")
80+
checksum = host.get("shasum") or ""
81+
if not archive_url:
82+
raise SystemExit(f"missing archive URL for version={version!r} host={host_key!r}")
83+
84+
print(archive_url)
85+
print(checksum)
86+
PY
87+
)"
88+
89+
archive_url="$(printf '%s\n' "$zig_metadata" | sed -n '1p')"
90+
expected_sha="$(printf '%s\n' "$zig_metadata" | sed -n '2p')"
91+
if [ -z "$archive_url" ]; then
92+
echo "failed to resolve Zig download URL" >&2
93+
exit 1
94+
fi
95+
96+
archive_name="${archive_url##*/}"
97+
archive_dir="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/zig-archive.XXXXXX")"
98+
archive_path="${archive_dir}/${archive_name}"
99+
extract_dir="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/zig-extract.XXXXXX")"
100+
trap 'rm -rf "$archive_dir"; rm -rf "$extract_dir"' EXIT
101+
102+
curl -fsSL --retry 3 --retry-all-errors "$archive_url" -o "$archive_path"
103+
104+
"$python_bin" - "$archive_path" "$expected_sha" <<'PY'
105+
import hashlib
106+
import sys
107+
108+
path = sys.argv[1]
109+
expected = sys.argv[2].strip().lower()
110+
if not expected:
111+
raise SystemExit(0)
112+
113+
digest = hashlib.sha256()
114+
with open(path, "rb") as handle:
115+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
116+
digest.update(chunk)
117+
118+
actual = digest.hexdigest().lower()
119+
if actual != expected:
120+
raise SystemExit(f"checksum mismatch for {path}: expected {expected}, got {actual}")
121+
PY
122+
123+
"$python_bin" - "$archive_path" "$extract_dir" <<'PY'
124+
import pathlib
125+
import sys
126+
import tarfile
127+
import zipfile
128+
129+
archive = pathlib.Path(sys.argv[1])
130+
destination = pathlib.Path(sys.argv[2])
131+
destination.mkdir(parents=True, exist_ok=True)
132+
133+
def ensure_within_destination(relative_name: str) -> None:
134+
target = (destination / relative_name).resolve()
135+
if destination.resolve() not in target.parents and target != destination.resolve():
136+
raise SystemExit(f"archive entry escapes destination: {relative_name}")
137+
138+
if archive.suffix == ".zip":
139+
with zipfile.ZipFile(archive) as handle:
140+
for member in handle.namelist():
141+
ensure_within_destination(member)
142+
handle.extractall(destination)
143+
else:
144+
with tarfile.open(archive, "r:*") as handle:
145+
for member in handle.getnames():
146+
ensure_within_destination(member)
147+
handle.extractall(destination)
148+
PY
149+
150+
extracted_dir="$(find "$extract_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
151+
if [ -z "$extracted_dir" ]; then
152+
echo "failed to extract Zig archive: $archive_url" >&2
153+
exit 1
154+
fi
155+
156+
rm -rf "$install_dir"
157+
mv "$extracted_dir" "$install_dir"
158+
fi
159+
160+
if [ -n "${GITHUB_PATH:-}" ]; then
161+
printf '%s\n' "$install_dir" >> "$GITHUB_PATH"
162+
else
163+
echo "GITHUB_PATH is not set; add this directory to PATH manually: $install_dir" >&2
164+
fi
165+
166+
"${install_dir}/${zig_bin}" version

.github/workflows/ci.yml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
name: CI
2-
on: [push]
2+
3+
env:
4+
ZIG_VERSION: "0.15.2"
5+
6+
on:
7+
push:
8+
branches: [main]
9+
pull_request:
10+
branches: [main]
11+
312
jobs:
413
test:
514
runs-on: ubuntu-latest
15+
defaults:
16+
run:
17+
shell: bash
618
steps:
719
- uses: actions/checkout@v4
8-
- name: Install dependencies
9-
run: |
10-
sudo snap install zig --classic --edge
11-
zig version
20+
21+
- name: Install Zig 0.15.2
22+
run: bash .github/scripts/install-zig.sh "${ZIG_VERSION}"
23+
1224
- name: non-blocking test
1325
run: zig build test -Dforce_blocking=false
1426
- name: blocking test

0 commit comments

Comments
 (0)