Files
gui/hanzo.yml
T
zeekayandHanzo Dev 58255138df ci: a runner label names the platform, not the org
hanzo-build-linux-amd64, lux-build-linux-amd64, zoo-build-linux-amd64 and
every other org-prefixed spelling all meant the same machine. Which org a
job belongs to does not change which host can build it, so the org bought
one pool name per org per arch and each could go stale on its own -- the
evo host alone answered to fourteen names for one label.

One vocabulary now: linux-amd64, linux-arm64, macos-arm64, win-amd64. The
generic labels every plain workflow uses (ubuntu-latest, self-hosted) are
untouched, so naive CI keeps working.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 12:25:29 -07:00

129 lines
6.5 KiB
YAML

# Canonical CI/CD config for hanzoai/gui — the ONE file that says how this repo
# gates itself. The only caller is `.hanzo/workflows/cicd.yml`, seven lines that
# import hanzoai/ci; everything real is here.
#
# WHERE THIS RUNS: git.hanzo.ai, not github.com. `gh api
# /orgs/hanzoai/actions/runners` returns total_count 0 — GitHub has no runner
# that answers the `linux-amd64` label the reusable asks for, so a
# `.github/workflows/cicd.yml` would queue forever. Gitea collects workflows
# from the FIRST of WORKFLOW_DIRS present in a commit, and `.hanzo/workflows`
# wins, which is also why `.github/workflows` is dark on Hanzo Git.
#
# NO `images:` AND NO `deploy:`. This is a package repo: its workspaces publish
# to npm, and the one surface it owns, gui.hanzo.ai, is a static export served
# straight off object storage by the `site:` lane below, which needs neither an
# image nor a pod.
test:
# bun, at the version package.json already pins. The reusable provisions Go,
# Node, Rust and Java for gates that need them — not bun — and every script in
# this repo runs through bun, so a gate here starts at `bun: command not
# found` without this. The version is READ, not retyped: packageManager is the
# one place this repo says which bun it is, and a second copy in this file
# would be free to drift from it.
#
# ~/.local/bin is already on PATH — the reusable puts it on $GITHUB_PATH when
# it provisions jq/yq — and every gate below is a separate `bash -c` child of
# that step, so linking bun into it is what makes bun visible to all of them.
- name: toolchain
run: |
set -euo pipefail
ver=$(node -p "require('./package.json').packageManager.split('@')[1]")
curl -fsSL https://bun.sh/install | BUN_INSTALL="$HOME/.bun" bash -s "bun-v$ver"
mkdir -p "$HOME/.local/bin"
ln -sf "$HOME/.bun/bin/bun" "$HOME/.local/bin/bun"
ln -sf "$HOME/.bun/bin/bunx" "$HOME/.local/bin/bunx"
bun --version
# Twice, deliberately, and not a superstition: the first install runs the root
# postinstall, which builds every package because a fresh checkout has no
# pkgs/compiler/vite-plugin/dist. Workspace bins only exist once that build has
# emitted them, so the symlinks into node_modules/.bin are made by the SECOND
# pass. `bun run check:hanzogui` calls ./node_modules/.bin/hanzogui and fails
# with "command not found" against a one-pass install. This is what
# .github/actions/install has always done; it is written down here now.
- name: install
run: |
set -euo pipefail
bun install --frozen-lockfile
bun install --frozen-lockfile
# Critical advisories only. Every one of them is pinned to a patched version
# through the root package.json "overrides", so this gates with no ignore list.
- name: audit
run: bun audit --audit-level critical
# manypkg + knip + the hanzogui dep check + project references + the shell's
# no-CSS-framework rule. Five assertions the repo already owns; `bun run check`
# is where it says so.
- name: check
run: bun run check
# oxfmt --check && oxlint.
- name: lint
run: bun run lint
# NO SKIP_TYPES, and that is the whole fix. `test:web` dependsOn ^build, and
# two packages (@hanzogui/web, @hanzogui/input) gate with `vitest --typecheck`
# — which needs its dependencies' .d.ts. Those live in <pkg>/types/, a
# gitignored artifact emitted only by a types build. The GitHub lane set
# SKIP_TYPES=1 on this job ("types are the checks job's business, not ours"),
# so ^build emitted JS only, @hanzogui/native resolved as an untyped module,
# React.useContext(NativeMenuContext) degraded to `unknown`, and the gate died
# in createComponent.tsx on a type error that is not in the source. Leaving
# SKIP_TYPES unset makes turbo build the declarations this gate reads.
#
# kitchen-sink is excluded because it is the integration suite (playwright
# against a dev server), not a unit suite.
- name: unit tests
run: |
set -euo pipefail
export NODE_OPTIONS=--max-old-space-size=6144
# --with-deps, and chromium only. Two suites here drive a real browser
# (apps/tests/integration, apps/tests/next-turbopack); neither declares
# `projects`, so playwright uses its default, chromium, and that is the
# only browser any of this needs — nothing asks for firefox or webkit.
#
# The deps are not optional on this fleet. Downloading the browser is not
# the same as being able to run it: the runner image
# (catthehacker/ubuntu:act-24.04) ships none of chromium's shared
# libraries, so a plain `playwright install` put the binary on disk and it
# then died with `error while loading shared libraries` / exit 127, which
# playwright reports as "Target page, context or browser has been closed"
# — a message that names neither the library nor the cause. GitHub's
# ubuntu-latest has those libs preinstalled, which is why this lane is the
# first place it could show up.
bunx playwright install --with-deps chromium
bun turbo run test:web --filter='!@hanzogui/kitchen-sink' --concurrency=1
# The native suites. This repo ships to react-native as much as to the web, and
# Hanzo Git lane it replaces gated only the web half — so the three packages
# that assert native behaviour (148 tests) ran nowhere Hanzo Git could see.
# Same three the GitHub lane names; carried here so one file gates both halves.
- name: native tests
run: |
set -euo pipefail
export NODE_OPTIONS=--max-old-space-size=6144
bun turbo run test:native \
--filter=@hanzogui/static-tests \
--filter=@hanzogui/core-test \
--filter=@hanzogui/components-test \
--concurrency=1
# gui.hanzo.ai, the docs, from apps/gui.hanzo.ai. The reusable's site lane
# publishes it to the Sites plane and `gui-static` in universe
# charts/app/values/hanzo/static-sites.yaml serves it: every route is a real
# file under dist/client, so that middleware runs with spaMode off.
#
# `on` is not decoration. It defaults to the empty list, and an unnamed branch
# publishes NOTHING — a main push would run the build, report success and ship
# no bytes. Naming main is what makes a merge reach the site.
#
# turbo, not the bare script: apps/gui.hanzo.ai imports workspace packages that
# must be built before it can be, and `one build` alone does not build them.
site:
slug: gui
dir: apps/gui.hanzo.ai/dist/client
on: [main]
build: bun turbo run build:web --filter=@hanzogui/dot-dev