diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index 4215b3d..0cda8e3 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -84,7 +84,7 @@ export const publishCommand = command({ // Scan for posts consola.start("Scanning for posts..."); - const posts = await scanContentDirectory(contentDir, config.frontmatter); + const posts = await scanContentDirectory(contentDir, config.frontmatter, config.ignore); consola.info(`Found ${posts.length} posts`); // Determine which posts need publishing @@ -213,7 +213,8 @@ export const publishCommand = command({ lastPublished: new Date().toISOString(), }; } catch (error) { - consola.error(` Error: ${error}`); + const errorMessage = error instanceof Error ? error.message : String(error); + consola.error(` Error publishing "${path.basename(post.filePath)}": ${errorMessage}`); errorCount++; } } diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index 13481c7..c515d4e 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -67,6 +67,7 @@ export function generateConfigTemplate(options: { publicationUri: string; pdsUrl?: string; frontmatter?: FrontmatterMapping; + ignore?: string[]; }): string { const config: Record = { siteUrl: options.siteUrl, @@ -99,6 +100,10 @@ export function generateConfigTemplate(options: { config.frontmatter = options.frontmatter; } + if (options.ignore && options.ignore.length > 0) { + config.ignore = options.ignore; + } + return JSON.stringify(config, null, 2); } diff --git a/packages/cli/src/lib/markdown.ts b/packages/cli/src/lib/markdown.ts index 99de982..8acf4f4 100644 --- a/packages/cli/src/lib/markdown.ts +++ b/packages/cli/src/lib/markdown.ts @@ -118,9 +118,20 @@ export async function getContentHash(content: string): Promise { return hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); } +function shouldIgnore(relativePath: string, ignorePatterns: string[]): boolean { + for (const pattern of ignorePatterns) { + const glob = new Glob(pattern); + if (glob.match(relativePath)) { + return true; + } + } + return false; +} + export async function scanContentDirectory( contentDir: string, - frontmatterMapping?: FrontmatterMapping + frontmatterMapping?: FrontmatterMapping, + ignorePatterns: string[] = [] ): Promise { const patterns = ["**/*.md", "**/*.mdx"]; const posts: BlogPost[] = []; @@ -132,6 +143,10 @@ export async function scanContentDirectory( cwd: contentDir, absolute: false, })) { + // Skip files matching ignore patterns + if (shouldIgnore(relativePath, ignorePatterns)) { + continue; + } const filePath = path.join(contentDir, relativePath); const file = Bun.file(filePath); diff --git a/packages/cli/src/lib/types.ts b/packages/cli/src/lib/types.ts index d3e6dd7..a8d055c 100644 --- a/packages/cli/src/lib/types.ts +++ b/packages/cli/src/lib/types.ts @@ -17,6 +17,7 @@ export interface PublisherConfig { pdsUrl?: string; identity?: string; // Which stored identity to use (matches identifier) frontmatter?: FrontmatterMapping; // Custom frontmatter field mappings + ignore?: string[]; // Glob patterns for files to ignore (e.g., ["_index.md", "**/drafts/**"]) } export interface Credentials {