Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8acb126f5 | |||
| 87ac67a70e | |||
| f838e0c8a7 | |||
| e520ba98ca | |||
| 21ecbca2e6 | |||
| 38c92e5fc7 | |||
| cee0328db5 | |||
| bbfc7cebf7 | |||
| 4a710ff294 | |||
| f1b5e1bac8 | |||
| b4438fec43 | |||
| aa040d1412 | |||
| d5820c43b0 | |||
| a1144605f3 | |||
| 43949b20a0 | |||
| 06b46c2e8f | |||
| ac5838f3dd | |||
| c8d1d3e1aa | |||
| b532519ad7 | |||
| b27aab20ee | |||
| 345f9be81a | |||
| 17e14a9fda | |||
| e7c1c922f7 | |||
| 954dc1d86e | |||
| a83efcda93 | |||
| 839c002ce0 | |||
| 0abef440fa | |||
| 9892d89c01 | |||
| 47163f690b | |||
| dc36fe0157 | |||
| fa65f7783e | |||
| b63aa5027b | |||
| 1110ff2e8c | |||
| a51a16c4da | |||
| 15c70f0e26 | |||
| b39977b74c |
+34
-13
@@ -75,6 +75,17 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
|
||||
|
||||
- name: Prune Docker to reclaim disk
|
||||
run: |
|
||||
# Remove stopped containers, dangling images, unused volumes/networks.
|
||||
# Do NOT prune build cache — that keeps Docker builds fast and under
|
||||
# the ~26min runner restart window. Selective pruning frees ~4-5GB
|
||||
# which is enough to prevent overlay2 "no space left on device" errors.
|
||||
docker container prune -f 2>&1 || true
|
||||
docker image prune -f 2>&1 || true
|
||||
docker volume prune -f 2>&1 || true
|
||||
df -h /
|
||||
|
||||
# ── El SDK setup ──────────────────────────────────────────────────────
|
||||
# Push builds: extract elb + elc + runtime from ci-base (always latest).
|
||||
# PR builds: use committed bin/elb-linux-amd64 + bin/elc-linux-amd64 + runtime/.
|
||||
@@ -90,7 +101,7 @@ jobs:
|
||||
docker rm "$CID"
|
||||
echo "ELB=/opt/el/dist/bin/elb" >> "$GITHUB_ENV"
|
||||
echo "ELC=/opt/el/dist/platform/elc" >> "$GITHUB_ENV"
|
||||
echo "EL_RUNTIME=/opt/el/el-compiler/runtime" >> "$GITHUB_ENV"
|
||||
echo "EL_RUNTIME=$GITHUB_WORKSPACE/runtime" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up El SDK from committed bin/ (PR builds)
|
||||
if: github.event_name == 'pull_request'
|
||||
@@ -146,6 +157,13 @@ jobs:
|
||||
rm -f src/js/el_runtime.js
|
||||
|
||||
# ── Docker build + smoke test ─────────────────────────────────────────
|
||||
#
|
||||
# PR builds: binary is compiled by committed bin/elb-linux-amd64 which
|
||||
# may lag behind the current El SDK. Smoke-testing that binary is
|
||||
# unreliable (glibc mismatch in Docker; potential codegen differences
|
||||
# when run directly). PRs only need to prove the code *compiles* and
|
||||
# the Docker image *builds* — the authoritative runtime check runs on
|
||||
# push to dev (ci-base SDK, always current).
|
||||
|
||||
- name: Compute image tag
|
||||
id: tag
|
||||
@@ -154,6 +172,12 @@ jobs:
|
||||
- name: Touch HTML placeholder files
|
||||
run: touch src/index.html src/about.html src/terms.html src/enterprise-terms.html
|
||||
|
||||
- name: Create soul-demo-image.tar placeholder
|
||||
# Dockerfile.stage COPYs this file (used by k3s at runtime).
|
||||
# We only need the COPY to succeed here; real tar is built by
|
||||
# build-stage.sh in the deploy pipeline.
|
||||
run: touch dist/soul-demo-image.tar
|
||||
|
||||
- name: Build Docker image (local only — no push)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -170,30 +194,27 @@ jobs:
|
||||
.
|
||||
|
||||
- name: Local smoke test
|
||||
# Push builds only: binary compiled from ci-base is current and
|
||||
# compatible with the runner glibc. Skipped for pull_request events
|
||||
# because the committed bin/elb may produce a binary that requires
|
||||
# a newer glibc than what the runner environment provides.
|
||||
if: github.event_name != 'pull_request'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
IMAGE="marketing:${{ steps.tag.outputs.tag }}"
|
||||
|
||||
docker run -d --name dev-smoke \
|
||||
-p 8080:8080 \
|
||||
-e PORT=8080 \
|
||||
-e NODE_ENV=production \
|
||||
-e LANDING_ROOT=/srv/landing \
|
||||
"$IMAGE"
|
||||
PORT=8080 dist/neuron-landing &
|
||||
SERVER_PID=$!
|
||||
|
||||
for i in $(seq 1 15); do
|
||||
STATUS=$(curl -sSo /dev/null -w "%{http_code}" --max-time 5 http://localhost:8080/ || echo "000")
|
||||
echo "Attempt $i/15: HTTP $STATUS"
|
||||
if [ "$STATUS" = "200" ]; then
|
||||
echo "Dev smoke test PASSED"
|
||||
docker stop dev-smoke && docker rm dev-smoke
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
echo "--- container logs ---"
|
||||
docker logs dev-smoke || true
|
||||
docker stop dev-smoke && docker rm dev-smoke || true
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
echo "Dev smoke test FAILED"
|
||||
exit 1
|
||||
|
||||
+62
-10
@@ -32,10 +32,16 @@ jobs:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Enforce dev-only source
|
||||
# stage only accepts merges from dev. Any PR from another branch fails
|
||||
# here before a single build step runs.
|
||||
# workflow_dispatch is exempt (allows manual redeploy of current stage).
|
||||
# Must run AFTER checkout — git commands require a cloned workspace.
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -43,7 +49,17 @@ jobs:
|
||||
echo "Merge commit: $COMMIT_MSG"
|
||||
# Gitea merge commits: "Merge pull request '...' (#N) from dev into stage"
|
||||
# Direct branch merges: "Merge branch 'dev' into stage"
|
||||
if echo "$COMMIT_MSG" | grep -qE " from dev into stage$| 'dev' into stage$"; then
|
||||
# tea pr merge with custom title: any subject line is possible, so
|
||||
# fall back to checking git parents — if the second parent is on dev
|
||||
# the merge came from dev regardless of the commit subject.
|
||||
SECOND_PARENT=$(git log -1 --pretty=format:"%P" HEAD | awk '{print $2}')
|
||||
FROM_DEV=""
|
||||
if [ -n "$SECOND_PARENT" ]; then
|
||||
if git merge-base --is-ancestor "$SECOND_PARENT" origin/dev 2>/dev/null; then
|
||||
FROM_DEV=1
|
||||
fi
|
||||
fi
|
||||
if echo "$COMMIT_MSG" | grep -qE " from dev into stage$| 'dev' into stage$" || [ -n "$FROM_DEV" ]; then
|
||||
echo "Source branch check: OK (merged from dev)"
|
||||
else
|
||||
echo "ERROR: stage only accepts merges from dev."
|
||||
@@ -51,11 +67,6 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Detect change type
|
||||
id: changetype
|
||||
run: |
|
||||
@@ -85,6 +96,17 @@ jobs:
|
||||
- name: Configure docker auth for Artifact Registry
|
||||
run: gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
|
||||
|
||||
- name: Prune Docker to reclaim disk
|
||||
run: |
|
||||
# Remove stopped containers, dangling images, unused volumes/networks.
|
||||
# Do NOT prune build cache — that keeps Docker builds fast and under
|
||||
# the ~26min runner restart window. Selective pruning frees ~4-5GB
|
||||
# which is enough to prevent overlay2 "no space left on device" errors.
|
||||
docker container prune -f 2>&1 || true
|
||||
docker image prune -f 2>&1 || true
|
||||
docker volume prune -f 2>&1 || true
|
||||
df -h /
|
||||
|
||||
- name: Compute image tag
|
||||
id: tag
|
||||
run: |
|
||||
@@ -106,14 +128,14 @@ jobs:
|
||||
if: steps.changetype.outputs.asset_only != 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker pull us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:stage
|
||||
CID=$(docker create us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:stage)
|
||||
docker pull us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:dev
|
||||
CID=$(docker create us-central1-docker.pkg.dev/neuron-785695/neuron-ci/ci-base:dev)
|
||||
sudo mkdir -p /opt/el
|
||||
docker cp "$CID:/opt/el" /opt/
|
||||
docker rm "$CID"
|
||||
echo "ELB=/opt/el/dist/bin/elb" >> "$GITHUB_ENV"
|
||||
echo "ELC=/opt/el/dist/platform/elc" >> "$GITHUB_ENV"
|
||||
echo "EL_RUNTIME=/opt/el/el-compiler/runtime" >> "$GITHUB_ENV"
|
||||
echo "EL_RUNTIME=$GITHUB_WORKSPACE/runtime" >> "$GITHUB_ENV"
|
||||
|
||||
# ── Build neuron-web binary ───────────────────────────────────────────
|
||||
|
||||
@@ -132,18 +154,48 @@ jobs:
|
||||
if: steps.changetype.outputs.asset_only != 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "ELC=$ELC"
|
||||
echo "EL_RUNTIME=$EL_RUNTIME"
|
||||
echo "el_runtime.js: $(ls -lh "$EL_RUNTIME/el_runtime.js" 2>&1)"
|
||||
cp "$EL_RUNTIME/el_runtime.js" src/js/
|
||||
mkdir -p dist/js
|
||||
for f in src/js/*.el; do
|
||||
[ -f "$f" ] || continue
|
||||
name=$(basename "$f" .el)
|
||||
"$ELC" --target=js --bundle --minify --obfuscate "$f" > "dist/js/${name}.js"
|
||||
echo "Compiling $f..."
|
||||
"$ELC" --target=js --bundle --minify --obfuscate "$f" > "dist/js/${name}.js" || {
|
||||
echo "elc FAILED on $f"
|
||||
exit 1
|
||||
}
|
||||
echo " compiled: $f -> dist/js/${name}.js"
|
||||
done
|
||||
rm -f src/js/el_runtime.js
|
||||
|
||||
# ── Docker build + push ───────────────────────────────────────────────
|
||||
|
||||
- name: Build soul-demo image tar
|
||||
# Dockerfile.stage COPYs dist/soul-demo-image.tar so k3s can import
|
||||
# soul-demo:local at runtime. We compile soul-demo from source on the
|
||||
# host runner (ci-base has gcc), build a minimal OCI image, and save it.
|
||||
# Moved AFTER JS compilation to avoid Docker memory pressure killing elc.
|
||||
if: steps.changetype.outputs.asset_only != 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Compile el_runtime.o and soul-demo on the host runner
|
||||
cc -O2 -DHAVE_CURL -c runtime/el_runtime.c -I runtime/ -o /tmp/el_runtime.o
|
||||
cc -O2 -rdynamic -DEL_SOUL_DEMO_BUILD \
|
||||
-I runtime/ \
|
||||
-o dist/soul-demo \
|
||||
dist/soul-demo.c dist/vessel_stubs.c /tmp/el_runtime.o \
|
||||
-lcurl -lpthread -ldl -lm -lssl -lcrypto
|
||||
echo "soul-demo compiled: $(ls -lh dist/soul-demo)"
|
||||
# Package as minimal OCI image for k3s import
|
||||
# --no-cache: prevents reuse of corrupted overlay2 layers from prior failed runs
|
||||
docker build --no-cache -f dist/Dockerfile.soul-demo -t soul-demo:local dist/
|
||||
docker save soul-demo:local -o dist/soul-demo-image.tar
|
||||
echo "soul-demo-image.tar: $(du -sh dist/soul-demo-image.tar | cut -f1)"
|
||||
docker rmi soul-demo:local 2>/dev/null || true
|
||||
|
||||
- name: Build and tag image
|
||||
if: steps.changetype.outputs.asset_only != 'true'
|
||||
run: |
|
||||
|
||||
+2
-1
@@ -38,12 +38,13 @@ RUN cc -O2 -DHAVE_CURL -c el_runtime.c -I. -o el_runtime.o
|
||||
COPY dist/soul-demo.c dist/vessel_stubs.c ./
|
||||
|
||||
RUN cc -O2 -rdynamic \
|
||||
-DEL_SOUL_DEMO_BUILD \
|
||||
-o soul-demo \
|
||||
soul-demo.c vessel_stubs.c el_runtime.o \
|
||||
-lcurl -lpthread -ldl -lm -lssl -lcrypto
|
||||
|
||||
# ── Download k3s binary ───────────────────────────────────────────────────────
|
||||
RUN curl -fL https://github.com/k3s-io/k3s/releases/download/v1.32.4%2Bk3s1/k3s -o /usr/local/bin/k3s \
|
||||
RUN curl -fL --retry 3 --retry-delay 10 https://github.com/k3s-io/k3s/releases/download/v1.32.4%2Bk3s1/k3s -o /usr/local/bin/k3s \
|
||||
&& chmod +x /usr/local/bin/k3s
|
||||
|
||||
# ── Stage 2: runtime image ────────────────────────────────────────────────────
|
||||
|
||||
Vendored
+8
@@ -1,6 +1,14 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# SKIP_K3S=1 — bypass k3s/soul-demo startup and go straight to neuron-web.
|
||||
# Used by the dev CI smoke test where the container runtime doesn't support
|
||||
# the kernel capabilities k3s requires (overlayfs / privileged mode).
|
||||
if [ "${SKIP_K3S:-0}" = "1" ]; then
|
||||
echo "[entrypoint] SKIP_K3S=1: starting neuron-web directly (no k3s/soul-demo)."
|
||||
exec /usr/local/bin/neuron-web
|
||||
fi
|
||||
|
||||
echo "[entrypoint] Starting k3s server (embedded soul-demo orchestrator)..."
|
||||
|
||||
# k3s server — single-node mode, disable unused components
|
||||
|
||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1819
-1800
File diff suppressed because it is too large
Load Diff
@@ -878,6 +878,32 @@ el_val_t __uuid_v4(void);
|
||||
/* Args */
|
||||
el_val_t __args_json(void);
|
||||
|
||||
/* ── neuron-web stubs (web_stubs.c) ──────────────────────────────────────────
|
||||
* Forward declarations so generated C (e.g. dist/main.c) sees the correct
|
||||
* el_val_t return type instead of an implicit int. Without these, the
|
||||
* ci-base elb (which does not emit extern-fn forward decls for stub-only
|
||||
* functions) produces truncated 32-bit returns on 64-bit Linux → segfault.
|
||||
*
|
||||
* Guarded by EL_SOUL_DEMO_BUILD: soul-demo.c includes this header but
|
||||
* defines its own (different-arity) versions of some of these functions.
|
||||
* Dockerfile.stage compiles soul-demo with -DEL_SOUL_DEMO_BUILD to skip
|
||||
* this block and avoid conflicting-types errors.
|
||||
*/
|
||||
#ifndef EL_SOUL_DEMO_BUILD
|
||||
el_val_t http_get_auth(el_val_t url, el_val_t tok);
|
||||
el_val_t http_post_auth(el_val_t url, el_val_t tok, el_val_t body);
|
||||
el_val_t http_post_auth_json(el_val_t url, el_val_t tok, el_val_t body);
|
||||
el_val_t http_delete_auth(el_val_t url, el_val_t bearer_tok, el_val_t apikey);
|
||||
el_val_t supabase_get(el_val_t project_url, el_val_t service_key, el_val_t table_and_query);
|
||||
el_val_t supabase_insert(el_val_t project_url, el_val_t service_key, el_val_t table, el_val_t row_json);
|
||||
el_val_t supabase_auth_user(el_val_t project_url, el_val_t anon_key, el_val_t user_jwt);
|
||||
el_val_t supabase_admin_invite(el_val_t project_url, el_val_t service_key, el_val_t body_json);
|
||||
el_val_t gcs_write(el_val_t bucket, el_val_t object_name, el_val_t content);
|
||||
el_val_t gcs_read(el_val_t bucket, el_val_t object_name);
|
||||
el_val_t cwd(void);
|
||||
el_val_t color_bold(el_val_t s);
|
||||
#endif /* EL_SOUL_DEMO_BUILD */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+5
-1
@@ -16,7 +16,11 @@ extern fn page_css() -> String
|
||||
extern fn page_ga_script() -> String
|
||||
extern fn page_schema() -> String
|
||||
|
||||
extern fn page_close() -> String
|
||||
extern fn _page_close_impl() -> String
|
||||
|
||||
fn page_close() -> String {
|
||||
return _page_close_impl()
|
||||
}
|
||||
|
||||
// el-html vessel — extern declarations (implementations in dist/elhtml_impl.c)
|
||||
extern fn el_meta(name: String, content: String) -> String
|
||||
|
||||
Reference in New Issue
Block a user