feat(miniapps): create-miniapp CLI + Storybook v10 + Vitest 集成 (#141) #144
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CD - Build and Deploy | |
| on: | |
| push: | |
| branches: [main] | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| channel: | |
| description: 'Build channel' | |
| required: false | |
| default: 'beta' | |
| type: choice | |
| options: | |
| - beta | |
| - stable | |
| # 设置 GITHUB_TOKEN 权限 | |
| permissions: | |
| contents: write | |
| pages: write | |
| id-token: write | |
| # 只允许一个并发部署 | |
| concurrency: | |
| group: 'pages' | |
| cancel-in-progress: false | |
| env: | |
| NODE_VERSION: '24' | |
| PNPM_VERSION: '10' | |
| jobs: | |
| # ==================== Self-hosted 快速构建 (无 action 下载) ==================== | |
| build-fast: | |
| if: vars.USE_SELF_HOSTED == 'true' | |
| runs-on: self-hosted | |
| timeout-minutes: 30 | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| channel: ${{ steps.channel.outputs.channel }} | |
| steps: | |
| - name: Setup GNU tar (required for actions/upload-pages-artifact) | |
| run: | | |
| # macOS uses BSD tar by default, but upload-pages-artifact requires GNU tar (gtar) | |
| if ! command -v gtar &> /dev/null; then | |
| brew install gnu-tar | |
| fi | |
| echo "$(brew --prefix gnu-tar)/libexec/gnubin" >> $GITHUB_PATH | |
| - name: Git checkout | |
| run: | | |
| if [ ! -d ".git" ]; then | |
| git clone https://github.com/${{ github.repository }}.git . | |
| fi | |
| git fetch origin ${{ github.sha }} --depth=1 --tags | |
| git checkout ${{ github.sha }} | |
| - name: Determine channel | |
| id: channel | |
| run: | | |
| if [[ "${{ github.ref }}" == refs/tags/v* ]]; then | |
| echo "channel=stable" >> $GITHUB_OUTPUT | |
| echo "Channel: stable (tag trigger)" | |
| elif [[ "${{ github.event.inputs.channel }}" == "stable" ]]; then | |
| echo "channel=stable" >> $GITHUB_OUTPUT | |
| echo "Channel: stable (manual trigger)" | |
| else | |
| echo "channel=beta" >> $GITHUB_OUTPUT | |
| echo "Channel: beta" | |
| fi | |
| - name: Get version | |
| id: version | |
| run: | | |
| if [[ "${{ github.ref }}" == refs/tags/v* ]]; then | |
| VERSION="${{ github.ref_name }}" | |
| VERSION="${VERSION#v}" | |
| else | |
| VERSION=$(node -p "require('./package.json').version") | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: Install & Build | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| CHANNEL: ${{ steps.channel.outputs.channel }} | |
| VITEPRESS_BASE: ${{ vars.VITEPRESS_BASE || format('/{0}/', github.event.repository.name) }} | |
| run: | | |
| pnpm install --frozen-lockfile | |
| # 类型检查和测试 | |
| pnpm turbo run typecheck:run test:run | |
| # 构建 Web 和 DWEB 版本 | |
| SERVICE_IMPL=web pnpm build | |
| rm -rf dist-web | |
| mv dist dist-web | |
| SERVICE_IMPL=dweb pnpm build | |
| rm -rf dist-dweb | |
| mv dist dist-dweb | |
| # Plaoc bundle | |
| if command -v plaoc &> /dev/null; then | |
| plaoc bundle ./dist-dweb -c ./ -o ./dists | |
| else | |
| mkdir -p dists | |
| cp -r dist-dweb/* dists/ | |
| fi | |
| # 准备 webapp 目录 | |
| mkdir -p docs/public/webapp docs/public/webapp-beta | |
| if [[ "$CHANNEL" == "stable" ]]; then | |
| cp -r dist-web/* docs/public/webapp/ | |
| if gh release download --pattern 'bfmpay-web-beta.zip' --dir /tmp -R ${{ github.repository }} 2>/dev/null; then | |
| unzip -q /tmp/bfmpay-web-beta.zip -d docs/public/webapp-beta/ | |
| else | |
| cp -r dist-web/* docs/public/webapp-beta/ | |
| fi | |
| else | |
| cp -r dist-web/* docs/public/webapp-beta/ | |
| if gh release download --pattern 'bfmpay-web.zip' --dir /tmp -R ${{ github.repository }} 2>/dev/null; then | |
| unzip -q /tmp/bfmpay-web.zip -d docs/public/webapp/ | |
| else | |
| cp -r dist-web/* docs/public/webapp/ | |
| fi | |
| fi | |
| # 构建 Storybook | |
| pnpm build-storybook | |
| mkdir -p docs/public/storybook | |
| cp -r storybook-static/* docs/public/storybook/ | |
| # 构建 VitePress | |
| pnpm docs:build | |
| # 准备 GitHub Pages | |
| mkdir -p gh-pages | |
| cp -r docs/.vitepress/dist/* gh-pages/ | |
| touch gh-pages/.nojekyll | |
| - name: Create release artifacts | |
| env: | |
| CHANNEL: ${{ steps.channel.outputs.channel }} | |
| run: | | |
| mkdir -p release | |
| VERSION="${{ steps.version.outputs.version }}" | |
| if [[ "$CHANNEL" == "stable" ]]; then | |
| cd dist-web && zip -r ../release/bfmpay-web.zip . && cd .. | |
| cp release/bfmpay-web.zip "release/bfmpay-web-${VERSION}.zip" | |
| if [ -d "dists" ] && [ "$(ls -A dists)" ]; then | |
| cd dists && zip -r ../release/bfmpay-dweb.zip . && cd .. | |
| else | |
| cd dist-dweb && zip -r ../release/bfmpay-dweb.zip . && cd .. | |
| fi | |
| cp release/bfmpay-dweb.zip "release/bfmpay-dweb-${VERSION}.zip" | |
| else | |
| cd dist-web && zip -r ../release/bfmpay-web-beta.zip . && cd .. | |
| cp release/bfmpay-web-beta.zip "release/bfmpay-web-${VERSION}-beta.zip" | |
| if [ -d "dists" ] && [ "$(ls -A dists)" ]; then | |
| cd dists && zip -r ../release/bfmpay-dweb-beta.zip . && cd .. | |
| else | |
| cd dist-dweb && zip -r ../release/bfmpay-dweb-beta.zip . && cd .. | |
| fi | |
| cp release/bfmpay-dweb-beta.zip "release/bfmpay-dweb-${VERSION}-beta.zip" | |
| fi | |
| - name: Upload GitHub Pages artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: gh-pages | |
| # 直接在 build job 中创建 release,避免跨 job 传递 artifact(self-hosted 下载很慢) | |
| - name: Create or Update Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.channel.outputs.channel == 'stable' && format('v{0}', steps.version.outputs.version) || 'beta' }} | |
| name: ${{ steps.channel.outputs.channel == 'stable' && format('BFM Pay v{0}', steps.version.outputs.version) || 'BFM Pay Beta' }} | |
| body: | | |
| ## BFM Pay ${{ steps.channel.outputs.channel == 'stable' && format('v{0}', steps.version.outputs.version) || 'Beta' }} | |
| ### 下载 | |
| - **Web 版本**: `bfmpay-web${{ steps.channel.outputs.channel == 'beta' && '-beta' || '' }}.zip` | |
| - **DWEB 版本**: `bfmpay-dweb${{ steps.channel.outputs.channel == 'beta' && '-beta' || '' }}.zip` | |
| ### 在线访问 | |
| - Web 应用 (stable): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/webapp/ | |
| - Web 应用 (beta): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/webapp-beta/ | |
| - 文档首页: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/ | |
| ### DWEB 安装 | |
| 在 DWEB 浏览器中打开以下链接安装: | |
| ``` | |
| dweb://install?url=https://github.com/${{ github.repository }}/releases/download/${{ steps.channel.outputs.channel == 'stable' && format('v{0}', steps.version.outputs.version) || 'beta' }}/bfmpay-dweb${{ steps.channel.outputs.channel == 'beta' && '-beta' || '' }}.zip | |
| ``` | |
| files: | | |
| release/* | |
| draft: false | |
| prerelease: ${{ steps.channel.outputs.channel == 'beta' }} | |
| generate_release_notes: ${{ steps.channel.outputs.channel == 'stable' }} | |
| # ==================== GitHub-hosted 标准构建 ==================== | |
| build-standard: | |
| if: vars.USE_SELF_HOSTED != 'true' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| channel: ${{ steps.channel.outputs.channel }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # 需要完整历史来下载 release | |
| - name: Determine channel | |
| id: channel | |
| run: | | |
| if [[ "${{ github.ref }}" == refs/tags/v* ]]; then | |
| echo "channel=stable" >> $GITHUB_OUTPUT | |
| echo "Channel: stable (tag trigger)" | |
| elif [[ "${{ github.event.inputs.channel }}" == "stable" ]]; then | |
| echo "channel=stable" >> $GITHUB_OUTPUT | |
| echo "Channel: stable (manual trigger)" | |
| else | |
| echo "channel=beta" >> $GITHUB_OUTPUT | |
| echo "Channel: beta" | |
| fi | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Get version | |
| id: version | |
| run: | | |
| if [[ "${{ github.ref }}" == refs/tags/v* ]]; then | |
| VERSION="${{ github.ref_name }}" | |
| VERSION="${VERSION#v}" | |
| else | |
| VERSION=$(node -p "require('./package.json').version") | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| - name: Type check | |
| run: pnpm typecheck | |
| - name: Run tests | |
| run: pnpm test | |
| # ===== 构建当前渠道的 Web 版本 ===== | |
| - name: Build Web version | |
| run: | | |
| SERVICE_IMPL=web pnpm build | |
| mv dist dist-web | |
| # ===== 构建 DWEB 版本 ===== | |
| - name: Build DWEB version | |
| run: | | |
| SERVICE_IMPL=dweb pnpm build | |
| mv dist dist-dweb | |
| - name: Install Plaoc CLI | |
| run: npm install -g @aspect/plaoc-cli || echo "Plaoc CLI not available" | |
| - name: Bundle DWEB with Plaoc | |
| continue-on-error: true | |
| run: | | |
| if command -v plaoc &> /dev/null; then | |
| plaoc bundle ./dist-dweb -c ./ -o ./dists | |
| echo "Plaoc bundle completed" | |
| else | |
| echo "Plaoc CLI not installed, using raw dist-dweb" | |
| mkdir -p dists | |
| cp -r dist-dweb/* dists/ | |
| fi | |
| # ===== 准备 VitePress 的 webapp 目录 ===== | |
| - name: Prepare webapp for VitePress | |
| env: | |
| CHANNEL: ${{ steps.channel.outputs.channel }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| echo "Current channel: $CHANNEL" | |
| # 当前构建的版本放到对应渠道目录 | |
| if [[ "$CHANNEL" == "stable" ]]; then | |
| # stable 构建:当前版本放 webapp/,尝试下载 beta | |
| mkdir -p docs/public/webapp | |
| cp -r dist-web/* docs/public/webapp/ | |
| echo "Copied current build to docs/public/webapp/ (stable)" | |
| # 尝试下载最新的 beta 版本(从 latest prerelease) | |
| mkdir -p docs/public/webapp-beta | |
| if gh release download --pattern 'bfmpay-web-beta.zip' --dir /tmp -R ${{ github.repository }} 2>/dev/null; then | |
| unzip -q /tmp/bfmpay-web-beta.zip -d docs/public/webapp-beta/ | |
| echo "Downloaded beta version from release" | |
| else | |
| # 如果没有 beta release,使用当前构建 | |
| cp -r dist-web/* docs/public/webapp-beta/ | |
| echo "No beta release found, using current build for webapp-beta" | |
| fi | |
| else | |
| # beta 构建:当前版本放 webapp-beta/,尝试下载 stable | |
| mkdir -p docs/public/webapp-beta | |
| cp -r dist-web/* docs/public/webapp-beta/ | |
| echo "Copied current build to docs/public/webapp-beta/ (beta)" | |
| # 尝试下载最新的 stable 版本 | |
| mkdir -p docs/public/webapp | |
| if gh release download --pattern 'bfmpay-web.zip' --dir /tmp -R ${{ github.repository }} 2>/dev/null; then | |
| unzip -q /tmp/bfmpay-web.zip -d docs/public/webapp/ | |
| echo "Downloaded stable version from release" | |
| else | |
| # 如果没有 stable release,使用当前构建 | |
| cp -r dist-web/* docs/public/webapp/ | |
| echo "No stable release found, using current build for webapp" | |
| fi | |
| fi | |
| # 显示准备好的目录 | |
| echo "=== webapp directory ===" | |
| ls -la docs/public/webapp/ | head -5 | |
| echo "=== webapp-beta directory ===" | |
| ls -la docs/public/webapp-beta/ | head -5 | |
| # ===== 构建 Storybook ===== | |
| - name: Build Storybook | |
| run: pnpm build-storybook | |
| - name: Prepare Storybook for VitePress | |
| run: | | |
| mkdir -p docs/public/storybook | |
| cp -r storybook-static/* docs/public/storybook/ | |
| echo "Storybook copied to docs/public/storybook/" | |
| # ===== 构建 VitePress 站点 ===== | |
| # Base path: 仓库变量 VITEPRESS_BASE,默认使用 /{repo_name}/ | |
| - name: Build VitePress site | |
| env: | |
| VITEPRESS_BASE: ${{ vars.VITEPRESS_BASE || format('/{0}/', github.event.repository.name) }} | |
| run: | | |
| echo "Building with VITEPRESS_BASE=$VITEPRESS_BASE" | |
| pnpm docs:build | |
| # ===== 准备 GitHub Pages ===== | |
| - name: Prepare GitHub Pages | |
| run: | | |
| # VitePress 输出目录 | |
| mkdir -p gh-pages | |
| cp -r docs/.vitepress/dist/* gh-pages/ | |
| # 禁用 Jekyll | |
| touch gh-pages/.nojekyll | |
| echo "=== GitHub Pages structure ===" | |
| find gh-pages -maxdepth 2 -type d | |
| # ===== 创建 Release 产物 ===== | |
| - name: Create release artifacts | |
| env: | |
| CHANNEL: ${{ steps.channel.outputs.channel }} | |
| run: | | |
| mkdir -p release | |
| VERSION="${{ steps.version.outputs.version }}" | |
| if [[ "$CHANNEL" == "stable" ]]; then | |
| # Stable: 创建不带 beta 后缀的文件 | |
| cd dist-web && zip -r ../release/bfmpay-web.zip . && cd .. | |
| cp release/bfmpay-web.zip "release/bfmpay-web-${VERSION}.zip" | |
| if [ -d "dists" ] && [ "$(ls -A dists)" ]; then | |
| cd dists && zip -r ../release/bfmpay-dweb.zip . && cd .. | |
| else | |
| cd dist-dweb && zip -r ../release/bfmpay-dweb.zip . && cd .. | |
| fi | |
| cp release/bfmpay-dweb.zip "release/bfmpay-dweb-${VERSION}.zip" | |
| else | |
| # Beta: 创建带 beta 后缀的文件 | |
| cd dist-web && zip -r ../release/bfmpay-web-beta.zip . && cd .. | |
| cp release/bfmpay-web-beta.zip "release/bfmpay-web-${VERSION}-beta.zip" | |
| if [ -d "dists" ] && [ "$(ls -A dists)" ]; then | |
| cd dists && zip -r ../release/bfmpay-dweb-beta.zip . && cd .. | |
| else | |
| cd dist-dweb && zip -r ../release/bfmpay-dweb-beta.zip . && cd .. | |
| fi | |
| cp release/bfmpay-dweb-beta.zip "release/bfmpay-dweb-${VERSION}-beta.zip" | |
| fi | |
| echo "=== Release artifacts ===" | |
| ls -la release/ | |
| # ===== 上传构建产物 ===== | |
| - name: Upload GitHub Pages artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: gh-pages | |
| - name: Upload release artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-${{ steps.channel.outputs.channel }}-${{ steps.version.outputs.version }} | |
| path: release/ | |
| retention-days: 30 | |
| # ==================== 部署到 GitHub Pages ==================== | |
| deploy-pages-fast: | |
| if: vars.USE_SELF_HOSTED == 'true' | |
| needs: build-fast | |
| runs-on: self-hosted | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| deploy-pages-standard: | |
| if: vars.USE_SELF_HOSTED != 'true' | |
| needs: build-standard | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| # ==================== 创建 Release (GitHub-hosted) ==================== | |
| create-release-standard: | |
| if: vars.USE_SELF_HOSTED != 'true' | |
| needs: build-standard | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download release artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-${{ needs.build-standard.outputs.channel }}-${{ needs.build-standard.outputs.version }} | |
| path: release/ | |
| - name: Create or Update Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.build-standard.outputs.channel == 'stable' && format('v{0}', needs.build-standard.outputs.version) || 'beta' }} | |
| name: ${{ needs.build-standard.outputs.channel == 'stable' && format('BFM Pay v{0}', needs.build-standard.outputs.version) || 'BFM Pay Beta' }} | |
| body: | | |
| ## BFM Pay ${{ needs.build-standard.outputs.channel == 'stable' && format('v{0}', needs.build-standard.outputs.version) || 'Beta' }} | |
| ### 下载 | |
| - **Web 版本**: `bfmpay-web${{ needs.build-standard.outputs.channel == 'beta' && '-beta' || '' }}.zip` | |
| - **DWEB 版本**: `bfmpay-dweb${{ needs.build-standard.outputs.channel == 'beta' && '-beta' || '' }}.zip` | |
| ### 在线访问 | |
| - Web 应用 (stable): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/webapp/ | |
| - Web 应用 (beta): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/webapp-beta/ | |
| - 文档首页: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/ | |
| ### DWEB 安装 | |
| 在 DWEB 浏览器中打开以下链接安装: | |
| ``` | |
| dweb://install?url=https://github.com/${{ github.repository }}/releases/download/${{ needs.build-standard.outputs.channel == 'stable' && format('v{0}', needs.build-standard.outputs.version) || 'beta' }}/bfmpay-dweb${{ needs.build-standard.outputs.channel == 'beta' && '-beta' || '' }}.zip | |
| ``` | |
| files: | | |
| release/* | |
| draft: false | |
| prerelease: ${{ needs.build-standard.outputs.channel == 'beta' }} | |
| generate_release_notes: ${{ needs.build-standard.outputs.channel == 'stable' }} |