name: CI on: push: branches: - main - Dev - 'feat/**' pull_request: workflow_dispatch: inputs: renderer_repo: description: 'Renderer repo (owner/name). Empty = vars.RENDERER_REPO or upstream default.' required: false default: '' renderer_ref: description: 'Renderer git ref. Empty = vars.RENDERER_REF or auto (main on client main, else Dev).' required: false default: '' # Opt into the Node.js 24 runtime for the JavaScript actions # (actions/checkout, actions/setup-node, …). Node 20 will be removed # from GitHub-hosted runners in September 2026; this env var asks the # runner to use Node 24 today so the workflow logs stop warning about # it on every run. env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' # Upstream renderer used as the fallback when nothing else is # configured. Override per-fork via the RENDERER_REPO / RENDERER_REF # repository variables (Settings → Secrets and variables → Actions → # Variables) or, for one-off runs, via the workflow_dispatch inputs. UPSTREAM_RENDERER_REPO: 'duckietm/Nitro_Render_V3' jobs: check: name: Type check + tests runs-on: ubuntu-latest steps: # The build/dev/typecheck setup expects the Nitro renderer SDK to # live as a sibling of this repo (see CLAUDE.md → Setup walkthrough). # Mirror that here by checking the client into /Nitro-V3 # and the renderer into /Nitro_Render_V3. - name: Checkout Nitro-V3 uses: actions/checkout@v4 with: path: Nitro-V3 # Resolve the renderer pairing with a clear precedence, from most # specific to most generic — no fork names or feature branches are # hardcoded in this workflow: # # 1. workflow_dispatch inputs (renderer_repo / renderer_ref) # → explicit manual override, wins outright. # 2. repository variables (vars.RENDERER_REPO / vars.RENDERER_REF) # → per-fork config set under Settings → Variables, applies # to push and pull_request runs without editing this file. # 3. dynamic, owner-aware default (no hardcoded fork name) # → /Nitro_Render_V3 when it carries # the resolved ref, else UPSTREAM_RENDERER_REPO. Ref is # `main` on a main build, otherwise `Dev`. So a fork's # client pairs with the fork's renderer when the companion # code lives there, and with upstream when it doesn't. # # The two repos must stay wire-aligned (composer/parser # signatures); pairing the client with a stale renderer is what # produced the "Expected 14-15 arguments, but got 16" failure on # the catalog edit composer. When a feature touches both repos, # point RENDERER_REPO/RENDERER_REF (or the dispatch inputs) at the # companion renderer branch. - name: Resolve renderer ref id: renderer env: IN_REPO: ${{ github.event.inputs.renderer_repo }} IN_REF: ${{ github.event.inputs.renderer_ref }} VAR_REPO: ${{ vars.RENDERER_REPO }} VAR_REF: ${{ vars.RENDERER_REF }} run: | # Dynamic, owner-aware renderer pairing — nothing is hardcoded to a # specific fork. The companion renderer is discovered from the # client repo's OWNER first, then the upstream fallback: "if the # companion code is on my fork, pair with my fork; otherwise pair # with upstream". For PRs the context is the base ref. # # Precedence (most specific wins): # 1. workflow_dispatch inputs (renderer_repo / renderer_ref) # 2. repo variables (vars.RENDERER_REPO / vars.RENDERER_REF) # 3. dynamic: /Nitro_Render_V3 when it carries the ref, # else ${UPSTREAM_RENDERER_REPO}. case "${GITHUB_EVENT_NAME}" in pull_request) CTX="${GITHUB_BASE_REF}" ;; *) CTX="${GITHUB_REF_NAME}" ;; esac # Branch-aware desired ref: main on a main build, else Dev. case "$CTX" in main) AUTO_REF="main" ;; *) AUTO_REF="Dev" ;; esac REF="$IN_REF" [ -z "$REF" ] && REF="$VAR_REF" [ -z "$REF" ] && REF="$AUTO_REF" # Probe whether has branch (remote-only, no checkout). has_ref() { git ls-remote --exit-code --heads "https://github.com/$1.git" "$2" >/dev/null 2>&1; } REPO="$IN_REPO" [ -z "$REPO" ] && REPO="$VAR_REPO" if [ -z "$REPO" ]; then OWN_REPO="${GITHUB_REPOSITORY_OWNER}/Nitro_Render_V3" if has_ref "$OWN_REPO" "$REF"; then REPO="$OWN_REPO" # companion lives on my own fork else REPO="$UPSTREAM_RENDERER_REPO" # fall back to upstream fi fi # Safety net: never pair against a repo/ref that doesn't exist. if ! has_ref "$REPO" "$REF"; then echo "::warning::renderer '$REPO' has no branch '$REF' — falling back to ${UPSTREAM_RENDERER_REPO}" REPO="$UPSTREAM_RENDERER_REPO" has_ref "$REPO" "$REF" || REF="Dev" fi echo "repo=$REPO" >> "$GITHUB_OUTPUT" echo "ref=$REF" >> "$GITHUB_OUTPUT" echo "Resolved renderer pairing: $REPO @ $REF (client ctx: $CTX, event: ${GITHUB_EVENT_NAME})" - name: Checkout Nitro_Render_V3 (sibling) uses: actions/checkout@v4 with: repository: ${{ steps.renderer.outputs.repo }} ref: ${{ steps.renderer.outputs.ref }} path: Nitro_Render_V3 - name: Setup Node 22 uses: actions/setup-node@v4 with: node-version: '22' cache: yarn cache-dependency-path: | Nitro-V3/yarn.lock Nitro_Render_V3/yarn.lock - name: Install renderer SDK deps working-directory: Nitro_Render_V3 run: yarn install --frozen-lockfile - name: Install client deps working-directory: Nitro-V3 run: yarn install --frozen-lockfile # The renderer SDK is consumed via a filesystem symlink in # node_modules/@nitrots/nitro-renderer; create it AFTER yarn # install (otherwise yarn would clean it up since the package # isn't declared in package.json). tsgo (TS 7 native preview) # then resolves the tsconfig `include` entry pointing at the # renderer's `src/**/*.ts`. # # Use an absolute path so the link target is unambiguous # regardless of the cwd that reads it. A relative target like # `../../../Nitro_Render_V3` resolves to # `Nitro-V3/Nitro_Render_V3` (one too few `..`), which doesn't # exist and makes tsgo report TS2307 across the entire src/. - name: Symlink renderer into client node_modules run: | mkdir -p Nitro-V3/node_modules/@nitrots ln -sfn "${{ github.workspace }}/Nitro_Render_V3" Nitro-V3/node_modules/@nitrots/nitro-renderer ls -la Nitro-V3/node_modules/@nitrots/ ls Nitro-V3/node_modules/@nitrots/nitro-renderer/packages/api/src/ | head -5 - name: Type check (tsgo) working-directory: Nitro-V3 run: yarn typecheck # Hook-order lint gate — the full yarn eslint emits ~900 pre-existing # baseline errors (brace style, indentation), so we use a focused # config that asserts only react-hooks/rules-of-hooks. Catches the # "hook below early-return" pattern that produced two production # crashes this session (CatalogPurchaseWidgetView, CatalogItemGridWidgetView). - name: ESLint (hook-order gate) working-directory: Nitro-V3 run: yarn lint:hooks - name: Vitest working-directory: Nitro-V3 run: yarn test --run