-
Notifications
You must be signed in to change notification settings - Fork 0
296 lines (268 loc) · 13.5 KB
/
Copy pathrelease.yml
File metadata and controls
296 lines (268 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
name: Release
# Trigger: push a v* tag (e.g., git tag v0.0.1 && git push origin v0.0.1).
#
# This pipeline is the twice-proven injection-scanner/mcp-hub cargo-zigbuild
# template adapted to tar.gz packaging: ONE self-hosted Linux host
# cross-compiles ALL targets via cargo-zigbuild (zig is host-arch-independent,
# so no per-arch runner, no Docker/cross, no macOS runner). Every job runs on
# UnityInFlow org self-hosted runners ONLY — ZERO GitHub-hosted runners
# (never any GitHub-hosted ubuntu/macos image anywhere, per CLAUDE.md).
#
# ── RUNNER DISPOSITION ─────────────────────────────────────────────────────────
# All jobs run serially on the single ARM64 orangepi runner: the Hetzner X64
# fleet (arc-runner-unityinflow) is intermittently offline (recurring ecosystem
# blocker, STATE.md carry-forward). cargo-zigbuild is host-arch-independent, so
# one board builds every triple. When the X64 fleet returns, `runs-on` can flip
# back to [arc-runner-unityinflow].
#
# ── ASSET CONTRACT ─────────────────────────────────────────────────────────────
# Assets are tarballs (agent-memory-<triple>.tar.gz) with the single
# `agent-memory` binary at the archive root — the Homebrew formula in
# UnityInFlow/homebrew-tap expects exactly this shape (a deliberate divergence
# from the injection-scanner analog's raw binaries).
#
# ── DARWIN DISPOSITION (DIST-01) ───────────────────────────────────────────────
# The two apple-darwin legs are HARD-required: DIST-01 mandates macOS
# arm64/x86_64 binaries, so a darwin failure fails the release (a deliberate
# divergence from the analog's experimental darwin legs). The darwin bundled-C
# cross-compile (sqlite3.c + sqlite-vec.c) is de-risked by the mandatory
# spike-cross-compile.yml gate, which MUST be green before any tag is pushed
# (RESEARCH Pitfall 1). Only the two musl legs are best-effort
# (continue-on-error) — gnu covers Linux if musl fails (RESEARCH Open Q2).
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
# Pinned toolchain for cargo-zigbuild cross-compilation (RESEARCH Pitfall 3).
# NEVER use "latest" — zig <-> cargo-zigbuild compatibility is version-coupled.
ZIG_VERSION: '0.14.1'
CARGO_ZIGBUILD_VERSION: '0.23.0'
jobs:
# ──────────────────────────────────────────────────────────────────────────
# JOB 1: test
# Full quality gate: fmt + clippy -D warnings + workspace tests + the same
# >80% line-coverage gate ci.yml enforces. Builds do not start until this
# passes — the tag must meet every gate main is held to.
# ──────────────────────────────────────────────────────────────────────────
test:
name: Test gate (fmt + clippy + test + coverage)
runs-on: [orangepi]
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: cargo fmt check
run: cargo fmt --check
- name: cargo clippy (deny warnings)
run: cargo clippy --workspace --all-targets -- -D warnings
- name: cargo test
run: cargo test --workspace
- name: Install cargo-llvm-cov
run: cargo install cargo-llvm-cov --locked
- name: Coverage gate (>80% lines)
run: cargo llvm-cov --workspace --fail-under-lines 80
# ──────────────────────────────────────────────────────────────────────────
# JOB 2: build-binaries
# ONE self-hosted Linux runner cross-compiles ALL 6 targets via
# cargo-zigbuild, serially (single orangepi board).
#
# The four DIST-01 targets (both apple-darwin + both linux-gnu) are
# HARD-required. Only the two musl legs may fail without failing the
# release (best-effort static-linux bonus).
# ──────────────────────────────────────────────────────────────────────────
build-binaries:
name: Build ${{ matrix.target }}
needs: test
runs-on: [orangepi]
# Only the musl legs are non-blocking; darwin + gnu legs hard-fail (DIST-01).
continue-on-error: ${{ matrix['continue-on-error'] }}
strategy:
# fail-fast disabled: surface ALL target failures in one run. The release
# job still hard-requires the 4 DIST-01 tarballs, so a partial required
# set never ships.
fail-fast: false
matrix:
include:
# ── REQUIRED (DIST-01): macOS arm64/x86_64 — hard-fail on error ──
- target: aarch64-apple-darwin
continue-on-error: false
- target: x86_64-apple-darwin
continue-on-error: false
# ── REQUIRED (DIST-01): Linux gnu x86_64/aarch64 — hard-fail ──
- target: x86_64-unknown-linux-gnu
continue-on-error: false
- target: aarch64-unknown-linux-gnu
continue-on-error: false
# ── BEST-EFFORT: static musl pair (RESEARCH Open Question 2) ──
- target: x86_64-unknown-linux-musl
continue-on-error: true
- target: aarch64-unknown-linux-musl
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install Rust stable + target
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install pinned zig + cargo-zigbuild
run: |
# Pinned versions (RESEARCH Pitfall 3): zig 0.14.1, cargo-zigbuild 0.23.0.
# Install zig from the official tarball matched to the HOST arch (the
# self-hosted runners have no pip3 -- orangepi is ARM64; a Hetzner X64
# runner would be x86_64). zig itself cross-compiles to all targets, so
# only the host arch matters here. Pin BOTH versions -- never `latest`.
set -euo pipefail
case "$(uname -m)" in
aarch64|arm64) ZIG_ARCH=aarch64 ;;
x86_64|amd64) ZIG_ARCH=x86_64 ;;
*) echo "unsupported host arch: $(uname -m)" >&2; exit 1 ;;
esac
# zig 0.14.0+ uses arch-first artifact naming: zig-<arch>-linux-<ver>.
ZIG_DIR="zig-${ZIG_ARCH}-linux-${ZIG_VERSION}"
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/${ZIG_DIR}.tar.xz" -o /tmp/zig.tar.xz
mkdir -p "$HOME/.zig" && tar -xJf /tmp/zig.tar.xz -C "$HOME/.zig"
echo "$HOME/.zig/${ZIG_DIR}" >> "$GITHUB_PATH"
"$HOME/.zig/${ZIG_DIR}/zig" version
cargo install --locked --version "${CARGO_ZIGBUILD_VERSION}" cargo-zigbuild
- name: Build (cargo zigbuild, cross-compiled from this Linux host)
run: cargo zigbuild --release --locked --target ${{ matrix.target }} -p agent-memory
- name: Smoke test (host-arch-aware --version; foreign-arch/darwin = presence-only)
run: |
set -euo pipefail
BIN="target/${{ matrix.target }}/release/agent-memory"
test -f "$BIN" || { echo "ERROR: $BIN missing"; exit 1; }
TARGET="${{ matrix.target }}"
case "$TARGET" in
*-apple-darwin)
# A macOS binary is never natively executable on a Linux host.
echo "apple-darwin build present -- presence-only (not executable on a Linux host)."
;;
*)
# Execute only when the target arch equals the runner arch —
# `Exec format error` otherwise (RESEARCH Pitfall 7, mcp-hub
# 03-04 precedent). Decide at runtime, never hardcode a triple.
TARGET_ARCH="${TARGET%%-*}" # x86_64 | aarch64
HOST_ARCH="$(uname -m)"; [ "$HOST_ARCH" = "arm64" ] && HOST_ARCH=aarch64
if [ "$TARGET_ARCH" = "$HOST_ARCH" ]; then
"$BIN" --version
else
echo "Cross-built $TARGET_ARCH on $HOST_ARCH host -- presence-only."
fi
;;
esac
- name: Package (agent-memory-<triple>.tar.gz, binary at archive root)
run: |
# Asset contract: the Homebrew formula downloads the tarball and runs
# `bin.install "agent-memory"` — the single binary must sit at the
# archive root with its plain name.
set -euo pipefail
OUT="agent-memory-${{ matrix.target }}.tar.gz"
STAGE="$(mktemp -d)"
cp "target/${{ matrix.target }}/release/agent-memory" "$STAGE/agent-memory"
chmod +x "$STAGE/agent-memory"
tar -czf "$OUT" -C "$STAGE" agent-memory
echo "Packaged: $OUT"
tar -tzf "$OUT"
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: ${{ matrix.target }}
path: agent-memory-${{ matrix.target }}.tar.gz
# ──────────────────────────────────────────────────────────────────────────
# JOB 3: release
# The 4 DIST-01 tarballs are HARD-required (fail loudly if any is missing).
# The two musl tarballs are included when present, otherwise warn-and-continue.
# Generates SHA256SUMS.txt over all present tarballs and creates the GitHub
# Release.
# ──────────────────────────────────────────────────────────────────────────
release:
name: Create GitHub Release
needs: [build-binaries]
runs-on: [orangepi]
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v5
with:
merge-multiple: true
path: artifacts/
- name: Validate required assets (DIST-01 hard gate) + musl disposition
run: |
set -euo pipefail
cd artifacts
# The four tarballs DIST-01 requires — any absence fails the release.
REQUIRED=(
"agent-memory-aarch64-apple-darwin.tar.gz"
"agent-memory-x86_64-apple-darwin.tar.gz"
"agent-memory-x86_64-unknown-linux-gnu.tar.gz"
"agent-memory-aarch64-unknown-linux-gnu.tar.gz"
)
for f in "${REQUIRED[@]}"; do
if test -f "$f"; then
echo "OK (required): $f"
else
echo "MISSING (required DIST-01 asset): $f"
exit 1
fi
done
# The two musl tarballs are best-effort (RESEARCH Open Question 2).
for f in \
"agent-memory-x86_64-unknown-linux-musl.tar.gz" \
"agent-memory-aarch64-unknown-linux-musl.tar.gz"; do
if test -f "$f"; then
echo "OK (musl bonus present): $f"
else
echo "::warning::musl static build unavailable -- gnu covers Linux (best-effort leg): $f"
fi
done
echo "All 4 required DIST-01 assets validated."
- name: Generate SHA256SUMS.txt (over all present tarballs)
run: |
set -euo pipefail
cd artifacts
: > SHA256SUMS.txt
for f in agent-memory-*.tar.gz; do
sha256sum "$f" >> SHA256SUMS.txt
done
echo "Generated SHA256SUMS.txt:"
cat SHA256SUMS.txt
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
files: |
artifacts/agent-memory-*.tar.gz
artifacts/SHA256SUMS.txt
generate_release_notes: true
body: |
## agent-memory release
Tarballs built entirely on UnityInFlow org self-hosted Linux runners
via `cargo zigbuild` (no GitHub-hosted runners). Each tarball holds
the single `agent-memory` binary at its root.
### Install via Homebrew (macOS + Linux)
```
brew install unityinflow/tap/agent-memory
```
### Manual install
| Platform | Asset |
|----------|-------|
| macOS arm64 (Apple Silicon) | `agent-memory-aarch64-apple-darwin.tar.gz` |
| macOS x86_64 (Intel) | `agent-memory-x86_64-apple-darwin.tar.gz` |
| Linux x86_64 (gnu) | `agent-memory-x86_64-unknown-linux-gnu.tar.gz` |
| Linux aarch64 (gnu) | `agent-memory-aarch64-unknown-linux-gnu.tar.gz` |
| Linux x86_64 (musl, static) | `agent-memory-x86_64-unknown-linux-musl.tar.gz` (if present) |
| Linux aarch64 (musl, static) | `agent-memory-aarch64-unknown-linux-musl.tar.gz` (if present) |
Verify with `SHA256SUMS.txt`, extract, and run:
```
shasum -a 256 -c SHA256SUMS.txt --ignore-missing
tar -xzf agent-memory-<triple>.tar.gz
./agent-memory --version
```
## Checksums
See `SHA256SUMS.txt` for verification.