Sitelet https://github.com/NodeOps-app/createos-sandbox-sdk/commit/1668abf884e8ed81125b0a63a1b4d8f3aa78da59
Skip to content

Commit 1668abf

Browse files
committed
ci: add manual example-run workflow (dispatch one example by number)
1 parent 01f4a4a commit 1668abf

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

‎.github/workflows/example-run.yml‎

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: example-run
2+
3+
# Manual, single-example runner. Pick one example by number in the Actions tab
4+
# and run just that one end-to-end against the live createos-sandbox control
5+
# plane — the same `bun index.ts` (create → verify → destroy) that examples.yml
6+
# runs, but on demand for one example instead of the full nightly matrix.
7+
#
8+
# Runner + reaper constraints mirror examples.yml: `runs-on: [createos]` boots a
9+
# throwaway microVM, ghar reaps any runner VM older than REAPER_MAX_AGE_MS
10+
# (30 min prod), so the job stays under `timeout-minutes: 25` and the example
11+
# itself is capped at `timeout 1200` (20 min).
12+
#
13+
# No push/PR trigger by design: this runs arbitrary example code with real
14+
# provider secrets, so it is manual-only (workflow_dispatch). Unlike examples.yml
15+
# there is no 10/36/37 exclusion — a human explicitly picking a number can run
16+
# any example, including the ones the nightly matrix skips.
17+
18+
on:
19+
workflow_dispatch:
20+
inputs:
21+
example:
22+
description: "Example number to run (e.g. 48 or 05)"
23+
required: true
24+
type: string
25+
26+
concurrency:
27+
group: example-run-${{ github.ref }}-${{ inputs.example }}
28+
cancel-in-progress: true
29+
30+
permissions:
31+
contents: read # checkout only; no write scope needed
32+
33+
jobs:
34+
run:
35+
runs-on: [createos]
36+
# Must stay under the ghar reaper's 30-min VM cutoff; example capped at
37+
# `timeout 1200` (20 min) below, leaving setup headroom.
38+
timeout-minutes: 25
39+
env:
40+
# createos-sandbox control plane (read by the SDK + most examples)
41+
CREATEOS_SANDBOX_API_KEY: ${{ secrets.CREATEOS_SANDBOX_API_KEY }}
42+
CREATEOS_SANDBOX_BASE_URL: ${{ secrets.CREATEOS_SANDBOX_BASE_URL }}
43+
# OpenAI / OpenAI-compatible
44+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
45+
OPENAI_API_URL: ${{ secrets.OPENAI_API_URL }}
46+
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
47+
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }}
48+
LLM_MODEL: ${{ secrets.LLM_MODEL }}
49+
# Anthropic
50+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
51+
ANTHROPIC_AUTH_TOKEN: ${{ secrets.ANTHROPIC_AUTH_TOKEN }}
52+
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
53+
ANTHROPIC_MODEL: ${{ secrets.ANTHROPIC_MODEL }}
54+
# S3-compatible bucket (examples 26, 38, 48)
55+
S3_BUCKET: ${{ secrets.S3_BUCKET }}
56+
S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
57+
S3_REGION: ${{ secrets.S3_REGION }}
58+
S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
59+
S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
60+
S3_USE_PATH_STYLE: ${{ secrets.S3_USE_PATH_STYLE }}
61+
steps:
62+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
63+
64+
# Resolve the number the user typed (48, or 05/5) to the example dir name.
65+
# Accepts a zero-padded or bare number; errors if it matches zero or >1 dir.
66+
- id: resolve
67+
env:
68+
EXAMPLE_INPUT: ${{ inputs.example }}
69+
run: |
70+
# Reject anything but digits so the value can't break out of the glob.
71+
if ! printf '%s' "$EXAMPLE_INPUT" | grep -qE '^[0-9]+$'; then
72+
echo "::error::example must be a number (got '$EXAMPLE_INPUT')"
73+
exit 1
74+
fi
75+
n="$EXAMPLE_INPUT"
76+
matches=$(cd examples && ls -d "${n}"-*/ 2>/dev/null | sed 's#/##')
77+
count=$(printf '%s' "$matches" | grep -c . || true)
78+
if [ "$count" -ne 1 ]; then
79+
echo "::error::input '$n' matched $count examples (expected 1):"
80+
printf '%s\n' "$matches"
81+
exit 1
82+
fi
83+
echo "dir=$matches" >> "$GITHUB_OUTPUT"
84+
echo "Resolved '$n' -> $matches" >> "$GITHUB_STEP_SUMMARY"
85+
86+
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
87+
with:
88+
bun-version: latest
89+
90+
- id: buncache
91+
run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
92+
93+
# Restore the shared cache seeded by examples.yml's discover job (same key
94+
# scheme). node_modules is NOT cached (the file:../ SDK symlink cycles);
95+
# the warm install below relinks it, hitting the restored store not network.
96+
- id: cache
97+
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
98+
with:
99+
path: |
100+
${{ steps.buncache.outputs.dir }}
101+
dist
102+
key: examples-deps-${{ hashFiles('src/**', 'tsconfig.json', 'bun.lock', 'examples/bun.lock', 'examples/package.json') }}
103+
104+
# Build dist/ if the cache (and thus dist/) was missing.
105+
- name: Build SDK (cache miss fallback)
106+
if: steps.cache.outputs.cache-hit != 'true'
107+
run: |
108+
bun install
109+
bun run build
110+
111+
# Warm install: links example deps from the restored store and recreates
112+
# the createos-sandbox-sdk -> dist/ symlink. No network on a cache hit.
113+
- name: Install example deps
114+
working-directory: examples
115+
run: bun install
116+
117+
# example 20 needs python3 + venv on PATH; distro python (setup-python's
118+
# prebuilt binaries don't match the microVM runner OS).
119+
- name: Set up Python (example 20)
120+
if: startsWith(steps.resolve.outputs.dir, '20-')
121+
run: |
122+
sudo apt-get update
123+
sudo apt-get install -y python3 python3-venv python3-pip
124+
125+
# S3-mounting examples; play.min.io purges buckets periodically.
126+
- name: Ensure S3 bucket (examples 26, 38, 48)
127+
if: startsWith(steps.resolve.outputs.dir, '26-') || startsWith(steps.resolve.outputs.dir, '38-') || startsWith(steps.resolve.outputs.dir, '48-')
128+
run: |
129+
curl -sSfL https://dl.min.io/client/mc/release/linux-amd64/mc -o /tmp/mc
130+
chmod +x /tmp/mc
131+
/tmp/mc alias set ci "$S3_ENDPOINT" "$S3_ACCESS_KEY" "$S3_SECRET_KEY"
132+
/tmp/mc mb --ignore-existing "ci/$S3_BUCKET"
133+
134+
- name: Run example ${{ steps.resolve.outputs.dir }}
135+
env:
136+
EXAMPLE: ${{ steps.resolve.outputs.dir }}
137+
run: |
138+
(cd "examples/$EXAMPLE" && timeout 1200 bun index.ts)
139+
echo "## ✅ $EXAMPLE passed" >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)