Skip to content

Commit 56862d1

Browse files
zrosenbauerclaude
andauthored
fix(packages/ui,packages/cli): fix FileTree build failure and add --ref to diff (#58)
* fix(packages/ui,packages/cli): fix FileTree build failure and add --ref to diff Bug 1: Pin rspress-plugin-file-tree to 1.0.3 (1.0.4 shipped without dist/) and copy its component files into @zpress/ui dist so Rspress webpack can resolve them at build time. Bug 2: Add --ref option to zpress diff that uses git diff instead of git status, enabling use as a Vercel ignoreCommand. When --ref is set and changes are detected, exits 1 to signal "proceed with build". Also upgrades all dependencies to latest (except mermaid, pinned to v10). Co-Authored-By: Claude <noreply@anthropic.com> * docs(packages/cli): improve diff --ref JSDoc with usage examples Co-Authored-By: Claude <noreply@anthropic.com> * fix(packages/cli): replace ternary with ts-pattern match in diff command Replace forbidden ternary expression with ts-pattern match() to select between gitDiffFiles and gitChangedFiles. Also disable prefer-destructuring lint rule for raw-copied MermaidRenderer component. Co-Authored-By: Claude <noreply@anthropic.com> * feat(packages/cli): add --verbose flag to build command When --verbose is passed, the build check skips output capture so Rspress/Rspack errors are printed directly to stdout/stderr. This makes it easier to diagnose build failures on CI. Co-Authored-By: Claude <noreply@anthropic.com> * fix(packages/ui): unpin rspress-plugin-file-tree back to ^1.0.4 The 1.0.4 package does ship dist/ — the earlier missing files were from a stale pnpm store. The copy rule in rslib.config.ts is the actual fix. Co-Authored-By: Claude <noreply@anthropic.com> * fix(packages/ui): copy FileTree chunks without clobbering dist root Copy rspress-plugin-file-tree chunk files (0~*.js) to dist root so FileTree.js relative imports resolve correctly. Exclude index.* and components/** to avoid overwriting our own build output. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5ee99d8 commit 56862d1

13 files changed

Lines changed: 369 additions & 231 deletions

File tree

.changeset/fix-cli-diff-ref.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@zpress/cli': minor
3+
---
4+
5+
Add `--ref` option to `zpress diff` for comparing between commits, enabling use as a Vercel `ignoreCommand`

.changeset/fix-ui-filetree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@zpress/ui': patch
3+
---
4+
5+
Fix missing FileTree component by pinning rspress-plugin-file-tree to 1.0.3 and copying its component files into the published dist

.oxlintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@
113113
{
114114
"files": ["**/MermaidRenderer.tsx"],
115115
"rules": {
116-
"unicorn/filename-case": "off"
116+
"unicorn/filename-case": "off",
117+
"prefer-destructuring": "off"
117118
}
118119
}
119120
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"@iconify-json/material-icon-theme": "^1.2.56",
3737
"@iconify-json/mdi": "^1.2.3",
3838
"@iconify-json/pixelarticons": "^1.2.4",
39-
"@iconify-json/simple-icons": "^1.2.74",
39+
"@iconify-json/simple-icons": "^1.2.75",
4040
"@iconify-json/skill-icons": "^1.2.4",
4141
"@iconify-json/vscode-icons": "^1.2.45",
4242
"@microsoft/api-extractor": "^7.57.7",

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"@zpress/templates": "workspace:*",
4747
"@zpress/ui": "workspace:*",
4848
"es-toolkit": "catalog:",
49-
"get-port": "^7.1.0",
49+
"get-port": "^7.2.0",
5050
"ts-pattern": "catalog:",
5151
"zod": "catalog:"
5252
},

packages/cli/src/commands/build.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ export const buildCommand = command({
1919
quiet: z.boolean().optional().default(false),
2020
clean: z.boolean().optional().default(false),
2121
check: z.boolean().optional().default(true),
22+
verbose: z.boolean().optional().default(false),
2223
}),
2324
handler: async (ctx) => {
24-
const { quiet, check } = ctx.args
25+
const { quiet, check, verbose } = ctx.args
2526
const paths = createPaths(process.cwd())
2627
ctx.logger.intro('zpress build')
2728

@@ -53,7 +54,7 @@ export const buildCommand = command({
5354
await sync(config, { paths, quiet: true })
5455

5556
ctx.logger.step('Building & checking for broken links...')
56-
const buildResult = await runBuildCheck({ config, paths })
57+
const buildResult = await runBuildCheck({ config, paths, verbose })
5758

5859
const passed = presentResults({ configResult, buildResult, logger: ctx.logger })
5960
if (!passed) {

packages/cli/src/commands/diff.ts

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { command } from '@kidd-cli/core'
44
import type { Section, ZpressConfig, Result } from '@zpress/core'
55
import { createPaths, hasGlobChars, loadConfig, normalizeInclude } from '@zpress/core'
66
import { uniq } from 'es-toolkit'
7+
import { match } from 'ts-pattern'
78
import { z } from 'zod'
89

910
const CONFIG_GLOBS = [
@@ -19,16 +20,42 @@ const CONFIG_GLOBS = [
1920
/**
2021
* Registers the `diff` CLI command to show changed files in watched directories.
2122
*
22-
* By default outputs a space-separated file list to stdout (suitable for
23-
* lefthook, scripts, and piping). Use `--pretty` for human-readable output.
23+
* By default uses `git status` to detect uncommitted changes and outputs a
24+
* space-separated file list to stdout (suitable for lefthook, scripts, and piping).
25+
*
26+
* Use `--ref <ref>` to compare between commits instead of checking working tree
27+
* status. This uses `git diff --name-only <ref> HEAD` under the hood and exits
28+
* with code 1 when changes are detected — matching the Vercel `ignoreCommand`
29+
* convention (exit 1 = proceed with build, exit 0 = skip).
30+
*
31+
* @example
32+
* ```bash
33+
* # Detect uncommitted changes (default, uses git status)
34+
* zpress diff
35+
*
36+
* # Compare against parent commit (CI / Vercel ignoreCommand)
37+
* zpress diff --ref HEAD^
38+
*
39+
* # Compare against main branch (PR context)
40+
* zpress diff --ref main
41+
*
42+
* # Human-readable output
43+
* zpress diff --ref main --pretty
44+
* ```
2445
*/
2546
export const diffCommand = command({
2647
description: 'Show changed files in configured source directories',
2748
options: z.object({
2849
pretty: z.boolean().optional().default(false),
50+
ref: z
51+
.string()
52+
.optional()
53+
.describe(
54+
'Git ref to compare against HEAD (e.g. HEAD^, main). Exits 1 when changes are detected.'
55+
),
2956
}),
3057
handler: async (ctx) => {
31-
const { pretty } = ctx.args
58+
const { pretty, ref } = ctx.args
3259
const paths = createPaths(process.cwd())
3360

3461
const [configErr, config] = await loadConfig(paths.repoRoot)
@@ -58,7 +85,12 @@ export const diffCommand = command({
5885
return
5986
}
6087

61-
const [gitErr, changed] = gitChangedFiles({ repoRoot: paths.repoRoot, dirs })
88+
const [gitErr, changed] = match(ref)
89+
.when(
90+
(r): r is string => r !== undefined,
91+
(r) => gitDiffFiles({ repoRoot: paths.repoRoot, dirs, ref: r })
92+
)
93+
.otherwise(() => gitChangedFiles({ repoRoot: paths.repoRoot, dirs }))
6294

6395
if (gitErr) {
6496
if (pretty) {
@@ -83,10 +115,15 @@ export const diffCommand = command({
83115
ctx.logger.step(`Watching ${dirs.length} path(s)`)
84116
ctx.logger.note(changed.join('\n'), `${changed.length} changed file(s)`)
85117
ctx.logger.outro('Done')
86-
return
118+
} else {
119+
process.stdout.write(`${changed.join(' ')}\n`)
87120
}
88121

89-
process.stdout.write(`${changed.join(' ')}\n`)
122+
// When --ref is used (e.g. as a Vercel ignoreCommand), exit 1 signals
123+
// "changes detected, proceed with build". Exit 0 (no changes) means skip.
124+
if (ref) {
125+
process.exit(1)
126+
}
90127
},
91128
})
92129

@@ -251,6 +288,40 @@ function stripQuotes(value: string): string {
251288
return trimmed
252289
}
253290

291+
/**
292+
* Run `git diff --name-only <ref> HEAD` scoped to the given directories and return changed file paths.
293+
*
294+
* Use this instead of `gitChangedFiles` when comparing between commits (e.g. for
295+
* CI ignore commands like Vercel's `ignoreCommand`), since `git status` only
296+
* detects uncommitted changes and always returns empty on clean checkouts.
297+
*
298+
* @private
299+
* @param params - Parameters for the git diff query
300+
* @param params.repoRoot - Absolute path to the repo root
301+
* @param params.dirs - Directories to scope the git diff to
302+
* @param params.ref - Git ref to compare against HEAD (e.g. `HEAD^`, `main`)
303+
* @returns Result tuple with changed file paths (repo-relative) or an error
304+
*/
305+
function gitDiffFiles(params: {
306+
readonly repoRoot: string
307+
readonly dirs: readonly string[]
308+
readonly ref: string
309+
}): Result<readonly string[]> {
310+
const [err, output] = execSilent({
311+
file: 'git',
312+
args: ['diff', '--name-only', params.ref, 'HEAD', '--', ...params.dirs],
313+
cwd: params.repoRoot,
314+
})
315+
if (err) {
316+
return [err, null]
317+
}
318+
if (!output) {
319+
return [null, []]
320+
}
321+
const files = output.split('\n').filter((line) => line.length > 0)
322+
return [null, files]
323+
}
324+
254325
/**
255326
* Run a command silently with an explicit argument array, returning a Result
256327
* tuple with trimmed stdout on success or an Error on failure.

packages/cli/src/lib/check.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ interface PresentResultsParams {
5454
interface RunBuildCheckParams {
5555
readonly config: ZpressConfig
5656
readonly paths: Paths
57+
readonly verbose?: boolean
5758
}
5859

5960
interface RunConfigCheckParams {
@@ -94,6 +95,10 @@ export function runConfigCheck(params: RunConfigCheckParams): ConfigCheckResult
9495
* @returns A `BuildCheckResult` with pass/fail status and any deadlinks found
9596
*/
9697
export async function runBuildCheck(params: RunBuildCheckParams): Promise<BuildCheckResult> {
98+
if (params.verbose) {
99+
return runBuildCheckVerbose(params)
100+
}
101+
97102
const { error, captured } = await captureOutput(() =>
98103
buildSiteForCheck({ config: params.config, paths: params.paths })
99104
)
@@ -157,6 +162,23 @@ export function presentResults(params: PresentResultsParams): boolean {
157162
// Private
158163
// ---------------------------------------------------------------------------
159164

165+
/**
166+
* Run the build check without capturing output, letting Rspress/Rspack
167+
* write directly to stdout/stderr so the full error details are visible.
168+
*
169+
* @private
170+
* @param params - Config and paths for the build
171+
* @returns A `BuildCheckResult` with pass/fail status
172+
*/
173+
async function runBuildCheckVerbose(params: RunBuildCheckParams): Promise<BuildCheckResult> {
174+
try {
175+
await buildSiteForCheck({ config: params.config, paths: params.paths })
176+
return { status: 'passed' }
177+
} catch (error) {
178+
return { status: 'error', message: toError(error).message }
179+
}
180+
}
181+
160182
/**
161183
* Strip ANSI escape codes from a string.
162184
*

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"gray-matter": "^4.0.3",
4949
"jiti": "^2.6.1",
5050
"js-yaml": "^4.1.1",
51-
"liquidjs": "^10.25.0",
51+
"liquidjs": "^10.25.1",
5252
"ts-pattern": "catalog:"
5353
},
5454
"devDependencies": {

packages/ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"@iconify-json/material-icon-theme": "^1.2.56",
5555
"@iconify-json/mdi": "^1.2.3",
5656
"@iconify-json/pixelarticons": "^1.2.4",
57-
"@iconify-json/simple-icons": "^1.2.74",
57+
"@iconify-json/simple-icons": "^1.2.75",
5858
"@iconify-json/skill-icons": "^1.2.4",
5959
"@iconify-json/vscode-icons": "^1.2.45",
6060
"@iconify/react": "^6.0.2",

0 commit comments

Comments
 (0)