Skip to content

Commit 7a0af59

Browse files
miguelgilaclaude
andauthored
feat: add --release flag to playground for pre-built binaries (#19)
* feat: add --release flag to playground for pre-built binaries The playground script can now download pre-built binaries from GitHub Releases instead of building from source, making it faster to try Reaper without any build toolchain. Defaults to latest release when no version is specified. Also clarifies in the README that no Rust toolchain is needed for the playground (builds happen inside Docker or are skipped entirely with --release). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add integration tests for --release resolution modes Extract resolve_latest_release() into scripts/lib/release-utils.sh so it can be sourced independently. Add test-playground-release.sh with 9 tests covering: - Latest release resolution via gh CLI (authenticated) - Latest release resolution via curl (unauthenticated GitHub API) - Consistency check between both methods - curl works without GITHUB_TOKEN credentials - Argument parsing: --release (bare), --release v0.2.4, --release --flag - --help output includes --release documentation - Graceful failure for nonexistent repos Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * ci: add playground release tests to CI pipeline Add a lightweight job to the Tests workflow that runs the --release resolution tests in parallel with existing jobs. No Rust, Docker, or Kind needed — just checkout and run. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1e26bec commit 7a0af59

File tree

5 files changed

+416
-13
lines changed

5 files changed

+416
-13
lines changed

.github/workflows/test.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,12 @@ jobs:
157157

158158
- name: Check formatting
159159
run: cargo fmt -- --check
160+
161+
playground-release:
162+
name: Playground Release Tests
163+
runs-on: ubuntu-latest
164+
steps:
165+
- uses: actions/checkout@v3
166+
167+
- name: Test --release resolution modes
168+
run: ./scripts/test-playground-release.sh

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,23 @@ Reaper is a containerd shim that runs processes directly on the host system whil
3939

4040
### Playground (try it locally)
4141

42-
Spin up a 3-node Kind cluster with Reaper pre-installed:
42+
Spin up a 3-node Kind cluster with Reaper pre-installed. No Rust toolchain needed.
43+
44+
**Quickest way** — download pre-built binaries from the latest [GitHub Release](https://github.com/miguelgila/reaper/releases):
4345

4446
```bash
4547
# Prerequisites: Docker, kind, kubectl, ansible (pip install ansible)
48+
./scripts/setup-playground.sh --release
49+
```
50+
51+
**Build from source** — compiles inside Docker (still no local Rust needed):
52+
53+
```bash
4654
./scripts/setup-playground.sh
4755
```
4856

49-
This builds Reaper, creates a Kind cluster with 1 control-plane + 2 worker nodes,
50-
installs the runtime on all nodes, and runs a smoke test. Once ready, try:
57+
Both create a Kind cluster with 1 control-plane + 2 worker nodes, install the
58+
runtime on all nodes, and run a smoke test. Once ready, try:
5159

5260
```bash
5361
kubectl run hello --rm -it --image=busybox --restart=Never \
@@ -267,12 +275,15 @@ The [examples/](examples/) directory contains runnable demos, each with a `setup
267275
- **Kubernetes cluster** with containerd runtime
268276
- **Root access** on cluster nodes (required for containerd shim installation)
269277

270-
**Local development / playground:**
278+
**Playground (no Rust needed):**
271279
- [Docker](https://docs.docker.com/get-docker/)
272280
- [kind](https://kind.sigs.k8s.io/) (Kubernetes in Docker)
273281
- [kubectl](https://kubernetes.io/docs/tasks/tools/)
274282
- [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/) (`pip install ansible`)
275283

284+
**Local development (building from source natively):**
285+
- All of the above, plus [Rust](https://www.rust-lang.org/tools/install) (toolchain version pinned in `rust-toolchain.toml`)
286+
276287
**Note:** Overlay filesystem is Linux-only. On macOS, the runtime compiles but overlay features are disabled.
277288

278289
## Testing

scripts/lib/release-utils.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env bash
2+
# release-utils.sh — GitHub release resolution helpers.
3+
# Sourced by setup-playground.sh and test scripts; do not execute directly.
4+
5+
GITHUB_REPO="${GITHUB_REPO:-miguelgila/reaper}"
6+
7+
# resolve_latest_release — Print the tag name of the latest GitHub release.
8+
#
9+
# Tries `gh` CLI first (handles auth and rate limits), then falls back to
10+
# the unauthenticated GitHub REST API via `curl` (60 requests/hour per IP).
11+
#
12+
# Outputs the tag (e.g., "v0.2.4") on stdout.
13+
# Returns non-zero and prints an error on stderr if resolution fails.
14+
resolve_latest_release() {
15+
local latest=""
16+
17+
# Path 1: gh CLI (if available)
18+
if command -v gh >/dev/null 2>&1; then
19+
latest=$(gh release view --repo "$GITHUB_REPO" --json tagName -q '.tagName' 2>/dev/null) || true
20+
fi
21+
22+
# Path 2: curl fallback (unauthenticated GitHub API)
23+
if [[ -z "${latest:-}" ]]; then
24+
latest=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" 2>/dev/null \
25+
| grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/') || true
26+
fi
27+
28+
if [[ -z "${latest:-}" ]]; then
29+
echo "ERROR: Could not determine latest release for $GITHUB_REPO" >&2
30+
return 1
31+
fi
32+
33+
echo "$latest"
34+
}

scripts/setup-playground.sh

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
# setup-playground.sh — Create a Reaper-enabled Kind cluster for manual testing.
33
#
44
# Usage:
5-
# ./scripts/setup-playground.sh # Create 3-node playground
5+
# ./scripts/setup-playground.sh # Build from source + create cluster
6+
# ./scripts/setup-playground.sh --release # Use latest GitHub release (no build)
7+
# ./scripts/setup-playground.sh --release v0.2.4 # Use specific GitHub release
68
# ./scripts/setup-playground.sh --cleanup # Delete playground cluster
79
# ./scripts/setup-playground.sh --cluster-name my-test # Custom cluster name
810
# ./scripts/setup-playground.sh --kind-config <path> # Custom Kind config
@@ -13,6 +15,7 @@
1315
# - kind (https://kind.sigs.k8s.io/)
1416
# - kubectl
1517
# - ansible-playbook (pip install ansible)
18+
# - curl (for --release mode)
1619
# - Run from the repository root
1720

1821
set -euo pipefail
@@ -25,6 +28,7 @@ KIND_CONFIG="" # empty = generate default 3-node config
2528
SKIP_BUILD=false
2629
QUIET=false
2730
CLEANUP=false
31+
RELEASE_VERSION="" # empty = build from source; "latest" or "vX.Y.Z" = download
2832

2933
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3034
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
@@ -86,6 +90,16 @@ while [[ $# -gt 0 ]]; do
8690
[[ ! -f "$KIND_CONFIG" ]] && fail "Kind config not found: $KIND_CONFIG"
8791
shift 2
8892
;;
93+
--release)
94+
# Accept optional version argument; default to "latest"
95+
if [[ -n "${2:-}" ]] && [[ "$2" != --* ]]; then
96+
RELEASE_VERSION="$2"
97+
shift 2
98+
else
99+
RELEASE_VERSION="latest"
100+
shift
101+
fi
102+
;;
89103
--skip-build)
90104
SKIP_BUILD=true
91105
shift
@@ -100,10 +114,11 @@ while [[ $# -gt 0 ]]; do
100114
echo "Create a Reaper-enabled Kind cluster for testing."
101115
echo ""
102116
echo "Options:"
117+
echo " --release [version] Use pre-built binaries from GitHub Releases (default: latest)"
103118
echo " --cleanup Delete the playground cluster"
104119
echo " --cluster-name <name> Cluster name (default: reaper-playground)"
105120
echo " --kind-config <path> Custom Kind config file (default: 3-node cluster)"
106-
echo " --skip-build Skip binary cross-compilation"
121+
echo " --skip-build Skip binary cross-compilation (when building from source)"
107122
echo " --quiet Suppress output (for scripted use)"
108123
echo " -h, --help Show this help"
109124
echo ""
@@ -198,12 +213,32 @@ else
198213
fi
199214

200215
# ---------------------------------------------------------------------------
201-
# Build static musl binaries
216+
# Resolve "latest" release version
202217
# ---------------------------------------------------------------------------
203-
if ! $SKIP_BUILD; then
204-
info "Building Reaper binaries for Kind nodes" | if_log
218+
# shellcheck source=lib/release-utils.sh
219+
source "$SCRIPT_DIR/lib/release-utils.sh"
220+
221+
if [[ -n "$RELEASE_VERSION" ]]; then
222+
if [[ "$RELEASE_VERSION" == "latest" ]]; then
223+
info "Resolving latest release..." | if_log
224+
RELEASE_VERSION=$(resolve_latest_release) || \
225+
fail "Could not determine latest release. Check https://github.com/${GITHUB_REPO}/releases or specify a version: --release v0.2.4"
226+
ok "Latest release: $RELEASE_VERSION" | if_log
227+
fi
228+
fi
205229

206-
cd "$REPO_ROOT"
230+
# ---------------------------------------------------------------------------
231+
# Obtain binaries (release download OR build from source)
232+
# ---------------------------------------------------------------------------
233+
cd "$REPO_ROOT"
234+
235+
if [[ -n "$RELEASE_VERSION" ]]; then
236+
# --release mode: delegate to install-reaper.sh which handles download
237+
info "Using pre-built release $RELEASE_VERSION (skipping build)" | if_log
238+
INSTALL_RELEASE_ARGS="--release $RELEASE_VERSION"
239+
240+
elif ! $SKIP_BUILD; then
241+
info "Building Reaper binaries for Kind nodes" | if_log
207242

208243
NODE_ID=$(docker ps --filter "name=${CLUSTER_NAME}-control-plane" --format '{{.ID}}')
209244
NODE_ARCH=$(docker exec "$NODE_ID" uname -m 2>&1) || fail "Cannot detect node architecture"
@@ -259,22 +294,24 @@ if ! $SKIP_BUILD; then
259294
fi
260295

261296
ok "Binaries built." | if_log
297+
INSTALL_RELEASE_ARGS=""
262298
else
263299
info "Skipping build (--skip-build)" | if_log
264-
cd "$REPO_ROOT"
300+
INSTALL_RELEASE_ARGS=""
265301
fi
266302

267303
# ---------------------------------------------------------------------------
268304
# Install Reaper on all nodes via Ansible
269305
# ---------------------------------------------------------------------------
270306
info "Installing Reaper runtime on all nodes" | if_log
271307

308+
# shellcheck disable=SC2086
272309
if $QUIET; then
273-
./scripts/install-reaper.sh --kind "$CLUSTER_NAME" >> "$LOG_FILE" 2>&1 || {
310+
./scripts/install-reaper.sh --kind "$CLUSTER_NAME" $INSTALL_RELEASE_ARGS >> "$LOG_FILE" 2>&1 || {
274311
fail "Ansible install failed. See $LOG_FILE for details."
275312
}
276313
else
277-
./scripts/install-reaper.sh --kind "$CLUSTER_NAME" 2>&1 | tee -a "$LOG_FILE" || {
314+
./scripts/install-reaper.sh --kind "$CLUSTER_NAME" $INSTALL_RELEASE_ARGS 2>&1 | tee -a "$LOG_FILE" || {
278315
fail "Ansible install failed. See $LOG_FILE for details."
279316
}
280317
fi

0 commit comments

Comments
 (0)