diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d5abdb2..0f039d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,6 +81,9 @@ jobs: - name: Build run: node --run build + - name: Prepare release + run: node --run release:prepare + - name: Publish to npm run: | pnpm --filter './packages/*' -r stage publish --tag ${{ github.event.inputs.npm_tag }} --no-git-checks diff --git a/package.json b/package.json index 93ea826..4c40375 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "format": "rs fmt && heading-case --write", "lint": "rs lint --type-check", "prepare": "node scripts/rs.js setup", + "release:prepare": "node scripts/prepare-release.js", "test": "pnpm --filter './packages/**' test" }, "devDependencies": { diff --git a/scripts/prepare-release.js b/scripts/prepare-release.js new file mode 100644 index 0000000..3038f11 --- /dev/null +++ b/scripts/prepare-release.js @@ -0,0 +1,74 @@ +#!/usr/bin/env node +import { spawn } from 'node:child_process'; +import { copyFile, mkdir, readdir, rm } from 'node:fs/promises'; +import path from 'node:path'; + +const rootDir = path.resolve(import.meta.dirname, '..'); +const websiteDir = path.join(rootDir, 'website'); +const websiteDistDir = path.join(websiteDir, 'doc_build'); +const packageDocsDir = path.join(rootDir, 'packages/rstack/dist/docs'); + +const run = (command, args) => + new Promise((resolve, reject) => { + const child = spawn(command, args, { + cwd: rootDir, + env: { + ...process.env, + RSPRESS_INJECT_LLMS_HINT: 'false', + }, + stdio: 'inherit', + }); + + child.on('error', reject); + child.on('exit', (code, signal) => { + if (code === 0) { + resolve(); + return; + } + + const reason = signal ? `signal ${signal}` : `exit code ${code}`; + reject(new Error(`${command} ${args.join(' ')} failed with ${reason}.`)); + }); + }); + +const collectMarkdownFiles = async (directory, relativeDir = '') => { + const entries = await readdir(directory, { withFileTypes: true }); + const files = []; + + for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) { + if (entry.isDirectory() && entry.name === 'zh') { + continue; + } + + const relativePath = path.join(relativeDir, entry.name); + const absolutePath = path.join(directory, entry.name); + + if (entry.isDirectory()) { + files.push(...(await collectMarkdownFiles(absolutePath, relativePath))); + } else if (entry.isFile() && path.extname(entry.name) === '.md') { + files.push(relativePath); + } + } + + return files; +}; + +const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; + +console.log('Building the website...'); +await run(pnpmCommand, ['--dir', websiteDir, 'build']); + +const markdownFiles = await collectMarkdownFiles(websiteDistDir); +if (markdownFiles.length === 0) { + throw new Error(`No English Markdown files found in ${websiteDistDir}.`); +} + +await rm(packageDocsDir, { recursive: true, force: true }); + +for (const relativePath of markdownFiles) { + const destination = path.join(packageDocsDir, relativePath); + await mkdir(path.dirname(destination), { recursive: true }); + await copyFile(path.join(websiteDistDir, relativePath), destination); +} + +console.log(`Copied ${markdownFiles.length} English Markdown files to ${packageDocsDir}.`); diff --git a/website/rstack.config.ts b/website/rstack.config.ts index c78997c..79821ca 100644 --- a/website/rstack.config.ts +++ b/website/rstack.config.ts @@ -6,6 +6,7 @@ const title = 'Rstack CLI'; const description = 'Rstack CLI brings the Rstack toolchain together with one CLI, one configuration, and one consistent workflow.'; const descriptionZh = 'Rstack CLI 通过统一的命令行、配置和工作流整合 Rstack 工具链。'; +const injectLlmsHint = process.env.RSPRESS_INJECT_LLMS_HINT !== 'false'; define.doc(async () => { const { pluginSass } = await import('@rsbuild/plugin-sass'); @@ -57,6 +58,9 @@ define.doc(async () => { pluginSitemap({ siteUrl }), ], themeConfig: { + llmsUI: { + injectLlmsHint, + }, socialLinks: [ { icon: 'github',