Skip to content

feat(miniapps): create-miniapp CLI + Storybook v10 + Vitest 集成 (#141) #144

feat(miniapps): create-miniapp CLI + Storybook v10 + Vitest 集成 (#141)

feat(miniapps): create-miniapp CLI + Storybook v10 + Vitest 集成 (#141) #144

Workflow file for this run

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' }}