Skip to content

Commit 72792d2

Browse files
committed
ci(registry): validate template sync before merge
1 parent 2734a75 commit 72792d2

File tree

4 files changed

+201
-12
lines changed

4 files changed

+201
-12
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
module: Registry Automation
3+
date: 2026-03-13
4+
problem_type: developer_experience
5+
component: tooling
6+
symptoms:
7+
- "`registry.yml` failed inside `pnpm templates:update --local` before workflow-level template checks even ran"
8+
- "`update-template.sh` died on `bun lint:fix` with template-local Biome unresolved-import noise"
9+
- "Local shadcn file installs could also stop for an interactive `npx shadcn@latest` prompt"
10+
root_cause: workflow_boundary_error
11+
resolution_type: tooling_change
12+
severity: medium
13+
tags:
14+
- templates
15+
- shadcn
16+
- registry
17+
- github-actions
18+
- ci
19+
- tooling
20+
---
21+
22+
# Template updater should generate, not own CI verification
23+
24+
## Problem
25+
26+
`registry.yml` was calling `pnpm templates:update --local`, and that helper script was also running its own `bun lint:fix` and `bun typecheck`.
27+
28+
That meant the workflow could fail inside the updater before the actual workflow checks ran. The failure looked like a registry sync problem, but it was really a bad boundary: the helper script was trying to be a mini CI pipeline.
29+
30+
## Root cause
31+
32+
Two things were wrong:
33+
34+
1. `update-template.sh` mixed generation with verification.
35+
2. local shadcn installs still had sharp edges:
36+
- `npx shadcn@latest` could prompt interactively in CI
37+
- local-file installs could write relative imports with `.ts` or `.tsx` extensions back into generated files
38+
39+
The first issue made the workflow brittle. The second made the updater noisy and flaky.
40+
41+
## Fix
42+
43+
Keep verification at the workflow layer.
44+
45+
In `tooling/scripts/update-template.sh`:
46+
47+
- use `npx --yes shadcn@latest add ...` so CI never stalls on an install prompt
48+
- normalize relative `.ts` and `.tsx` import specifiers after local-file installs
49+
- support `TEMPLATE_SKIP_VERIFY=true` to skip the script-local `bun lint:fix` and `bun typecheck`
50+
51+
In the workflows:
52+
53+
- set `TEMPLATE_SKIP_VERIFY=true` when running `pnpm templates:update --local`
54+
- run template builds after sync at the workflow level instead of inside the helper
55+
56+
That keeps the updater focused on generation and keeps CI responsible for CI.
57+
58+
## Why this works
59+
60+
The workflow now has one clear boundary:
61+
62+
- updater script: mutate template files
63+
- workflow: decide what to verify and when to fail
64+
65+
So a registry sync no longer dies because the helper script wandered into unrelated template lint/typecheck noise.
66+
67+
## Gotchas
68+
69+
### Don’t patch template-local Biome config as a workaround
70+
71+
That just moved the mess around and widened lint scope in ugly ways. The problem was not “templates need special Biome config.” The problem was “the wrong layer was running verification.”
72+
73+
### `gh act` still needs Docker even for dry runs
74+
75+
`gh act -n` was not a useful escape hatch here. It still tried to talk to Docker and failed immediately when the daemon was down.
76+
77+
## Verification
78+
79+
These commands passed after the fix:
80+
81+
```bash
82+
pnpm --filter www rd
83+
TEMPLATE_SKIP_VERIFY=true pnpm templates:update --local
84+
cd templates/plate-template && bun run build
85+
cd templates/plate-playground-template && bun run build
86+
bash -n tooling/scripts/update-template.sh
87+
```
88+
89+
`gh act` could not fully run on this machine because Docker was unavailable:
90+
91+
```bash
92+
gh act push -W .github/workflows/registry.yml -j update-registry
93+
```
94+
95+
It failed with:
96+
97+
```text
98+
Cannot connect to the Docker daemon at unix:///var/run/docker.sock
99+
```

.github/workflows/registry.yml

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,79 @@ on:
1111
- 'apps/www/scripts/**'
1212
- 'apps/www/src/app/globals.css'
1313
- 'apps/www/src/registry/**'
14+
pull_request:
15+
types:
16+
- opened
17+
- synchronize
18+
- reopened
19+
paths:
20+
- '.github/actions/**'
21+
- '.github/workflows/registry.yml'
22+
- 'apps/www/package.json'
23+
- 'apps/www/scripts/**'
24+
- 'apps/www/src/app/globals.css'
25+
- 'apps/www/src/registry/**'
1426

1527
permissions:
1628
contents: write
1729

1830
jobs:
31+
validate-registry:
32+
name: Validate Registry
33+
runs-on: ubuntu-latest
34+
if: ${{ github.event_name == 'pull_request' && github.repository == 'udecode/plate' && github.event.pull_request.title != '[Release] Version packages' }}
35+
36+
concurrency:
37+
group: ${{ github.workflow }}-validate-${{ github.event.pull_request.number || github.ref }}
38+
cancel-in-progress: true
39+
40+
steps:
41+
- name: 📥 Checkout Repo
42+
uses: actions/checkout@v4
43+
44+
- name: ♻️ Setup Node.js
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: 22
48+
49+
- uses: oven-sh/setup-bun@v2
50+
name: Install bun
51+
with:
52+
bun-version: 1.3.9
53+
54+
- name: 📦 Monorepo install
55+
uses: ./.github/actions/pnpm-install
56+
with:
57+
link-workspace-packages: 'true'
58+
59+
- name: 🏗 Build Registry
60+
run: pnpm --filter www build:registry && pnpm --filter www build:tw
61+
62+
- name: 🏗 Build local dev registry
63+
run: pnpm --filter www rd
64+
65+
- name: 🔄 Update templates
66+
env:
67+
TEMPLATE_SKIP_VERIFY: 'true'
68+
run: pnpm templates:update --local
69+
70+
- name: ✅ Run template CI
71+
run: |
72+
cd templates/plate-template
73+
bun install --no-frozen-lockfile
74+
bun run build
75+
76+
cd ../plate-playground-template
77+
bun install --no-frozen-lockfile
78+
bun run build
79+
1980
update-registry:
2081
name: Update Registry
2182
runs-on: ubuntu-latest
22-
if: ${{ github.repository == 'udecode/plate' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[skip release]') }}
83+
if: ${{ github.event_name == 'push' && github.repository == 'udecode/plate' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[skip release]') }}
2384

2485
concurrency:
25-
group: ${{ github.workflow }}-${{ github.ref }}
86+
group: ${{ github.workflow }}-publish-${{ github.ref }}
2687
cancel-in-progress: true
2788

2889
steps:
@@ -79,6 +140,8 @@ jobs:
79140

80141
- name: 🔄 Update templates
81142
if: ${{ steps.changesets.outputs.present != 'true' }}
143+
env:
144+
TEMPLATE_SKIP_VERIFY: 'true'
82145
run: pnpm templates:update --local
83146

84147
- name: 🔍 Detect template changes

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ jobs:
107107
- name: 🔄 Update templates
108108
id: update-templates
109109
continue-on-error: true
110+
env:
111+
TEMPLATE_SKIP_VERIFY: 'true'
110112
run: pnpm templates:update --local
111113

112114
- name: 🔍 Detect template changes

tooling/scripts/update-template.sh

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ USE_LOCAL=false
77
MODE="${1:-basic}"
88
USE_LOCAL_FILES=false
99
LOCAL_REGISTRY_DIR=""
10+
RUN_VERIFY=true
1011

1112
# Check for --local flag
1213
if [[ "${1:-}" == "--local" ]]; then
@@ -16,6 +17,10 @@ elif [[ "${2:-}" == "--local" ]]; then
1617
USE_LOCAL=true
1718
fi
1819

20+
if [[ "${TEMPLATE_SKIP_VERIFY:-false}" == "true" ]]; then
21+
RUN_VERIFY=false
22+
fi
23+
1924
# Determine registry prefix
2025
if [[ -n "${TEMPLATE_REGISTRY_URL:-}" ]]; then
2126
REGISTRY_PREFIX="${TEMPLATE_REGISTRY_URL%/}"
@@ -42,6 +47,18 @@ get_registry_item() {
4247
echo "$REGISTRY_PREFIX/$name"
4348
}
4449

50+
normalize_relative_ts_imports() {
51+
local root="$1"
52+
53+
if ! command -v rg >/dev/null 2>&1; then
54+
return
55+
fi
56+
57+
while IFS= read -r file; do
58+
perl -0pi -e "s/from '((?:\\.?\\.\\/)[^']+)\\.(?:tsx|ts)'/from '\\1'/g; s/from \"((?:\\.?\\.\\/)[^\"]+)\\.(?:tsx|ts)\"/from \"\\1\"/g" "$file"
59+
done < <(rg -l "from ['\"](?:\\.?\\.\\/)[^'\"]+\\.(?:ts|tsx)['\"]" "$root")
60+
}
61+
4562
# Map mode to template and registry
4663
case "$MODE" in
4764
basic)
@@ -59,10 +76,11 @@ case "$MODE" in
5976
echo " ai - Updates plate-playground-template with @plate/editor-ai"
6077
echo ""
6178
echo "Options:"
62-
echo " --local - Use local registry (http://localhost:3000/rd/...)"
79+
echo " --local - Use prepared local registry files from apps/www/public/rd"
6380
echo ""
6481
echo "Environment:"
6582
echo " TEMPLATE_REGISTRY_URL - Override the registry prefix (for example: http://127.0.0.1:3210/r)"
83+
echo " TEMPLATE_SKIP_VERIFY - Skip bun lint:fix and bun typecheck after generation"
6684
exit 1
6785
;;
6886
esac
@@ -97,19 +115,26 @@ echo "Adding $REGISTRY_NAME via shadcn..."
97115
if [[ "$USE_LOCAL_FILES" == true ]]; then
98116
(
99117
cd "$LOCAL_REGISTRY_DIR"
100-
npx shadcn@latest add "$REGISTRY_NAME" --cwd "$TEMPLATE_DIR" -o
118+
npx --yes shadcn@latest add "$REGISTRY_NAME" --cwd "$TEMPLATE_DIR" -o
101119
)
102120
else
103-
npx shadcn@latest add "$REGISTRY_NAME" -o
121+
npx --yes shadcn@latest add "$REGISTRY_NAME" -o
104122
fi
105123

106-
# Run lint:fix
107-
echo "Running bun lint:fix..."
108-
bun lint:fix
124+
# shadcn local-file installs can reintroduce relative `.ts/.tsx` import extensions.
125+
normalize_relative_ts_imports "$TEMPLATE_DIR/src"
126+
127+
if [[ "$RUN_VERIFY" == true ]]; then
128+
echo "Running bun lint:fix..."
129+
bun lint:fix
109130

110-
# Run typecheck
111-
echo "Running bun typecheck..."
112-
bun typecheck
131+
echo "Running bun typecheck..."
132+
bun typecheck
133+
134+
echo "✅ Done! Packages updated, $REGISTRY_NAME added, linted, and typechecked in $TEMPLATE_NAME."
135+
else
136+
echo "⏭️ Skipping template-local lint/typecheck (TEMPLATE_SKIP_VERIFY=true)."
137+
echo "✅ Done! Packages updated and $REGISTRY_NAME added in $TEMPLATE_NAME."
138+
fi
113139

114-
echo "✅ Done! Packages updated, $REGISTRY_NAME added, linted, and typechecked in $TEMPLATE_NAME."
115140
cd "$BASE"

0 commit comments

Comments
 (0)