From a78878f48d7e8c3b2ec0bdbfd4208ca88e74d852 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 19:49:46 +0800 Subject: [PATCH 1/2] ci: add fast/standard pattern for all CI/CD jobs CI changes: - Rename 'checks' to 'checks-fast' and 'checks-standard' - checks-fast runs on self-hosted when USE_SELF_HOSTED=true - checks-standard runs on ubuntu-latest as fallback CD changes: - Add 'build-fast' job for self-hosted runner (no action downloads) - Keep 'build-standard' for GitHub-hosted runners - Split deploy-pages into deploy-pages-fast/deploy-pages-standard - Split create-release into create-release-fast/create-release-standard - Uses turbo for caching in build-fast - Single combined 'Install & Build' step for faster execution --- .github/workflows/cd.yml | 227 ++++++++++++++++++++++++++++++++++++--- .github/workflows/ci.yml | 36 +++---- 2 files changed, 230 insertions(+), 33 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1ebb91d72..3ab09f339 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -32,8 +32,149 @@ env: PNPM_VERSION: '10' jobs: - # ==================== 构建 ==================== - build: + # ==================== 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: 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 + mv dist dist-web + + SERVICE_IMPL=dweb pnpm build + 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 + + - 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-hosted 标准构建 ==================== + build-standard: + if: vars.USE_SELF_HOSTED != 'true' runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.version }} @@ -248,8 +389,23 @@ jobs: retention-days: 30 # ==================== 部署到 GitHub Pages ==================== - deploy-pages: - needs: build + 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: @@ -262,28 +418,69 @@ jobs: uses: actions/deploy-pages@v4 # ==================== 创建 Release ==================== - create-release: - needs: build + create-release-fast: + if: vars.USE_SELF_HOSTED == 'true' + needs: build-fast + runs-on: self-hosted + + steps: + - name: Download release artifacts + uses: actions/download-artifact@v4 + with: + name: release-${{ needs.build-fast.outputs.channel }}-${{ needs.build-fast.outputs.version }} + path: release/ + + - name: Create or Update Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.build-fast.outputs.channel == 'stable' && format('v{0}', needs.build-fast.outputs.version) || 'beta' }} + name: ${{ needs.build-fast.outputs.channel == 'stable' && format('BFM Pay v{0}', needs.build-fast.outputs.version) || 'BFM Pay Beta' }} + body: | + ## BFM Pay ${{ needs.build-fast.outputs.channel == 'stable' && format('v{0}', needs.build-fast.outputs.version) || 'Beta' }} + + ### 下载 + - **Web 版本**: `bfmpay-web${{ needs.build-fast.outputs.channel == 'beta' && '-beta' || '' }}.zip` + - **DWEB 版本**: `bfmpay-dweb${{ needs.build-fast.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-fast.outputs.channel == 'stable' && format('v{0}', needs.build-fast.outputs.version) || 'beta' }}/bfmpay-dweb${{ needs.build-fast.outputs.channel == 'beta' && '-beta' || '' }}.zip + ``` + files: | + release/* + draft: false + prerelease: ${{ needs.build-fast.outputs.channel == 'beta' }} + generate_release_notes: ${{ needs.build-fast.outputs.channel == 'stable' }} + + 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.outputs.channel }}-${{ needs.build.outputs.version }} + 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.outputs.channel == 'stable' && format('v{0}', needs.build.outputs.version) || 'beta' }} - name: ${{ needs.build.outputs.channel == 'stable' && format('BFM Pay v{0}', needs.build.outputs.version) || 'BFM Pay Beta' }} + 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.outputs.channel == 'stable' && format('v{0}', needs.build.outputs.version) || 'Beta' }} + ## BFM Pay ${{ needs.build-standard.outputs.channel == 'stable' && format('v{0}', needs.build-standard.outputs.version) || 'Beta' }} ### 下载 - - **Web 版本**: `bfmpay-web${{ needs.build.outputs.channel == 'beta' && '-beta' || '' }}.zip` - - **DWEB 版本**: `bfmpay-dweb${{ needs.build.outputs.channel == 'beta' && '-beta' || '' }}.zip` + - **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/ @@ -293,10 +490,10 @@ jobs: ### DWEB 安装 在 DWEB 浏览器中打开以下链接安装: ``` - dweb://install?url=https://github.com/${{ github.repository }}/releases/download/${{ needs.build.outputs.channel == 'stable' && format('v{0}', needs.build.outputs.version) || 'beta' }}/bfmpay-dweb${{ needs.build.outputs.channel == 'beta' && '-beta' || '' }}.zip + 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.outputs.channel == 'beta' }} - generate_release_notes: ${{ needs.build.outputs.channel == 'stable' }} + prerelease: ${{ needs.build-standard.outputs.channel == 'beta' }} + generate_release_notes: ${{ needs.build-standard.outputs.channel == 'stable' }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55730f398..30dea7280 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,29 +110,29 @@ jobs: fi # ==================== 状态汇总 (分支保护需要) ==================== - checks: - runs-on: ubuntu-latest - needs: [ci-fast, ci-standard] - if: always() + # 使用 checks-fast 在 self-hosted 上快速汇总,checks-standard 作为备选 + checks-fast: + if: vars.USE_SELF_HOSTED == 'true' + runs-on: self-hosted + needs: [ci-fast] steps: - name: Check results run: | - FAST="${{ needs.ci-fast.result }}" - STD="${{ needs.ci-standard.result }}" - - if [[ "$FAST" == "failure" ]] || [[ "$STD" == "failure" ]]; then + if [[ "${{ needs.ci-fast.result }}" == "failure" ]]; then echo "CI failed!" exit 1 fi - - if [[ "$FAST" == "success" ]] || [[ "$STD" == "success" ]]; then - echo "All checks passed!" - exit 0 - fi - - if [[ "$FAST" == "skipped" ]] && [[ "$STD" == "skipped" ]]; then - echo "Error: Both CI jobs were skipped" + echo "All checks passed!" + + checks-standard: + if: vars.USE_SELF_HOSTED != 'true' + runs-on: ubuntu-latest + needs: [ci-standard] + steps: + - name: Check results + run: | + if [[ "${{ needs.ci-standard.result }}" == "failure" ]]; then + echo "CI failed!" exit 1 fi - - echo "CI completed" + echo "All checks passed!" From ef583c296c0570940c571f1d76ca9cdc06ac171b Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 19:52:48 +0800 Subject: [PATCH 2/2] ci: add checks aggregator for branch protection --- .github/workflows/ci.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30dea7280..4472dca1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: fi # ==================== 状态汇总 (分支保护需要) ==================== - # 使用 checks-fast 在 self-hosted 上快速汇总,checks-standard 作为备选 + # checks-fast 在 self-hosted 上快速汇总 checks-fast: if: vars.USE_SELF_HOSTED == 'true' runs-on: self-hosted @@ -124,6 +124,7 @@ jobs: fi echo "All checks passed!" + # checks-standard 在 GitHub-hosted 上汇总 checks-standard: if: vars.USE_SELF_HOSTED != 'true' runs-on: ubuntu-latest @@ -136,3 +137,26 @@ jobs: exit 1 fi echo "All checks passed!" + + # checks 是分支保护需要的 job,聚合 fast/standard 结果 + checks: + runs-on: ubuntu-latest + needs: [checks-fast, checks-standard] + if: always() + steps: + - name: Check results + run: | + FAST="${{ needs.checks-fast.result }}" + STD="${{ needs.checks-standard.result }}" + + if [[ "$FAST" == "failure" ]] || [[ "$STD" == "failure" ]]; then + echo "CI failed!" + exit 1 + fi + + if [[ "$FAST" == "success" ]] || [[ "$STD" == "success" ]]; then + echo "All checks passed!" + exit 0 + fi + + echo "CI completed"