Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@ if [ -n "$STAGED_CSS" ]; then
echo "$STAGED_CSS" | tr '\n' '\0' | xargs -0 npx stylelint
fi

# Rebuild dist bundles and stage them.
#
# dist/*.css is gitignored on main (built by `npm run build`, served via
# the dist branch + Releases — see .gitignore), so `git add` on those
# paths errors out and, under `set -e`, aborts every commit. Only stage
# outputs that are actually tracked; skip ignored ones. This keeps the
# rebuild-and-stage behaviour for any context where dist IS tracked
# without breaking commits where it isn't.
node scripts/bundle.js
outputs=$(node -e "const c=require('./bundle.config.json'); const b=Array.isArray(c.bundles)?c.bundles:[c]; process.stdout.write(b.map(x=>x.output).join('\n'))")
echo "$outputs" | while IFS= read -r f; do
[ -n "$f" ] || continue
if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
git add "$f"
fi
done
# Rebuild any generated artifacts whose sources changed and re-stage the outputs.
# Registration lives in scripts/artifacts.json — add entries there, not here.
node scripts/check-artifacts.js --fix
31 changes: 5 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ jobs:
name: dist
path: dist/

docs-freshness:
name: Verify generated docs
artifacts-freshness:
name: Verify all generated artifacts
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
Expand All @@ -50,31 +52,8 @@ jobs:
node-version: 22
cache: npm
- run: npm ci
- run: npm run docs
- run: npm run audit:check
- run: git diff --exit-code docs/tokens.md || (echo "::error::docs/tokens.md is stale — run 'npm run docs' and commit" && exit 1)
- run: git diff --exit-code docs/classes.md || (echo "::error::docs/classes.md is stale — run 'npm run docs' and commit" && exit 1)
- run: git diff --exit-code plugins/SLASHED-for-WP/integrations/bricks/data/inventory.json || (echo "::error::inventory.json is stale — run 'npm run docs' and commit" && exit 1)
- run: git diff --exit-code plugins/SLASHED-for-WP/data/classes-hints.json || (echo "::error::classes-hints.json is stale — run 'npm run docs' and commit" && exit 1)

editor-app-freshness:
name: Verify editor app build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
cache-dependency-path: plugins/SLASHED-for-WP/integrations/bricks/editor-app/package-lock.json
- run: npm ci
working-directory: plugins/SLASHED-for-WP/integrations/bricks/editor-app
- run: npm run build
working-directory: plugins/SLASHED-for-WP/integrations/bricks/editor-app
- run: git diff --exit-code plugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.js || (echo "::error::assets/editor-app/app.js is stale — run 'npm run build' in editor-app/ and commit" && exit 1)
- run: git diff --exit-code plugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.css || (echo "::error::assets/editor-app/app.css is stale — run 'npm run build' in editor-app/ and commit" && exit 1)
- run: node scripts/check-artifacts.js --check

test:
name: Regression tests
Expand Down
35 changes: 35 additions & 0 deletions scripts/artifacts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[
{
"name": "CSS bundles + docs",
"srcPrefixes": ["core/", "optional/"],
"buildCmd": "node scripts/bundle.js && npm run docs",
"outputs": [
"docs/tokens.md",
"docs/classes.md",
"plugins/SLASHED-for-WP/integrations/bricks/data/inventory.json",
"plugins/SLASHED-for-WP/data/classes-hints.json"
]
},
{
"name": "editor-app",
"srcPrefixes": ["plugins/SLASHED-for-WP/integrations/bricks/editor-app/src/"],
"cwd": "plugins/SLASHED-for-WP/integrations/bricks/editor-app",
"installCmd": "npm ci --silent",
"buildCmd": "npm run build --silent",
"outputs": [
"plugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.js",
"plugins/SLASHED-for-WP/integrations/bricks/assets/editor-app/app.css"
]
},
{
"name": "admin-app",
"srcPrefixes": ["plugins/SLASHED-for-WP/integrations/bricks/admin-app/src/"],
"cwd": "plugins/SLASHED-for-WP/integrations/bricks/admin-app",
"installCmd": "npm ci --silent",
"buildCmd": "npm run build --silent",
"outputs": [
"plugins/SLASHED-for-WP/integrations/bricks/assets/admin-app/app.js",
"plugins/SLASHED-for-WP/integrations/bricks/assets/admin-app/app.css"
]
}
]
75 changes: 75 additions & 0 deletions scripts/check-artifacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env node
/**
* Ensures all generated/compiled artifacts are in sync with their sources.
*
* Modes:
* --fix (pre-commit) Run only the builds whose sources are staged, then
* stage the outputs. Skips untracked outputs silently.
* --check (CI) Run every build unconditionally, then assert git diff is
* clean for each output. Exits non-zero on any staleness.
*
* To register a new build artifact, add an entry to scripts/artifacts.json.
*/

'use strict';

const { execSync, execFileSync } = require('child_process');
const { readFileSync } = require('fs');
const { resolve } = require('path');

const root = resolve(__dirname, '..');
const artifacts = JSON.parse(readFileSync(resolve(root, 'scripts/artifacts.json'), 'utf8'));
const mode = process.argv.includes('--check') ? 'check' : 'fix';

function run(cmd, cwd) {
execSync(cmd, { cwd: cwd || root, stdio: 'inherit', shell: true });
}

function gitFile(...args) {
return execFileSync('git', args, { cwd: root, encoding: 'utf8' });
}

function isTracked(path) {
try { gitFile('ls-files', '--error-unmatch', path); return true; } catch { return false; }
}

if (mode === 'fix') {
const staged = new Set(
gitFile('diff', '--cached', '--name-only', '--diff-filter=ACM')
.trim().split('\n').filter(Boolean)
);

for (const artifact of artifacts) {
const triggered = artifact.srcPrefixes.some(prefix => [...staged].some(f => f.startsWith(prefix)));
if (!triggered) continue;

console.log(`[artifacts] ${artifact.name} sources changed — rebuilding…`);
run(artifact.buildCmd, artifact.cwd ? resolve(root, artifact.cwd) : root);

for (const out of artifact.outputs) {
if (isTracked(out)) gitFile('add', out);
}
}
} else {
let failed = false;

for (const artifact of artifacts) {
console.log(`[artifacts] Checking ${artifact.name}…`);
// In CI, run the full install+build; locally (--fix) only buildCmd is used.
const cmd = artifact.installCmd
? `${artifact.installCmd} && ${artifact.buildCmd}`
: artifact.buildCmd;
run(cmd, artifact.cwd ? resolve(root, artifact.cwd) : root);

for (const out of artifact.outputs) {
try {
gitFile('diff', '--exit-code', '--', out);
} catch {
console.error(`::error::${out} is stale — rebuild ${artifact.name} and commit`);
failed = true;
}
}
}

if (failed) process.exit(1);
}