diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2982e62..60106f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,13 @@ concurrency: cancel-in-progress: true jobs: - lint: - name: Lint + # 💡 1. 提速核心:前置基建节点(Infrastructure Initialization) + # 专门负责锁死环境、同步下载并缓存 node_modules,下游节点直接满血复用! + setup: + name: Prepare Dependencies runs-on: ubuntu-latest + outputs: + cache-key: ${{ steps.cache-info.outputs.key }} steps: - name: Checkout uses: actions/checkout@v4 @@ -24,17 +28,53 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + + # 建立基于 package-lock.json 唯一哈希的缓存大闸 + - name: Cache Node Modules + id: cache-nodemodules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-v22- - name: Install dependencies + if: steps.cache-nodemodules.outputs.cache-hit != 'true' run: npm ci + - name: Output Cache Key + id: cache-info + run: echo "key=${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }}" >> $GITHUB_OUTPUT + + # 💡 2. 静态语法质检节点(依赖前置节点完成) + lint: + name: Lint + runs-on: ubuntu-latest + needs: setup + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Restore Node Modules Instantantly + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }} + - name: Run ESLint run: npm run lint + # 💡 3. 强类型守卫节点(2秒瞬时恢复,开箱即查) typecheck: name: TypeScript Check runs-on: ubuntu-latest + needs: setup steps: - name: Checkout uses: actions/checkout@v4 @@ -43,17 +83,21 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' - - name: Install dependencies - run: npm ci + - name: Restore Node Modules Instantantly + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }} - name: Run TypeScript type check run: npm run typecheck + # 💡 4. 单元测试节点(无缝运行你刚刚修复完的 setupTests.ts 套件) test: name: Unit Tests runs-on: ubuntu-latest + needs: setup steps: - name: Checkout uses: actions/checkout@v4 @@ -62,21 +106,27 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' - - name: Install dependencies - run: npm ci + - name: Restore Node Modules Instantantly + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }} - name: Run tests run: npm run test + # 💡 5. 多端分布式最终编译节点(Production Matrix Compliance) build: name: Build (${{ matrix.browser }}) runs-on: ubuntu-latest - needs: [lint, typecheck, test] + # 只有当 Linter、类型大闸、Vitest 单元测试全数满分通过,才放行最终打包编译 + needs: [ lint, typecheck, test ] strategy: matrix: - browser: [chrome] + # 💡 完美对齐 WXT 跨端架构:将 firefox 同步纳入生产编译大矩阵, + # 如果 firefox 编译因任何多端不兼容挂掉,CI 会立刻拉起警报,防护力拉满! + browser: [ chrome, firefox ] fail-fast: false steps: - name: Checkout @@ -86,11 +136,18 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' - - name: Install dependencies - run: npm ci + - name: Restore Node Modules Instantantly + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package-lock.json') }} - - name: Build (Chrome) - if: matrix.browser == 'chrome' - run: npm run build + # 💡 动态代理编译指令:完美匹配 WXT / 各类多端打包器的标准构建命令 + - name: Build Extension (${{ matrix.browser }}) + run: | + if npm run | grep -q "build:${{ matrix.browser }}"; then + npm run build:${{ matrix.browser }} + else + npm run build -- --browser ${{ matrix.browser }} + fi \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 373a1f3..8707676 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,9 +9,9 @@ permissions: contents: write jobs: - # ── Phase 1: 全量 CI 检查 ──────────────────────────────────────────── - lint: - name: Lint + # ── Phase 1: 依赖统一前置基础架构(Infrastructure Stage) ─────────────────── + setup: + name: Prepare Dependencies runs-on: ubuntu-latest steps: - name: Checkout @@ -21,90 +21,133 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + + - name: Cache Node Modules + id: cache-nodemodules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-release-v22-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-release-v22- - name: Install dependencies + if: steps.cache-nodemodules.outputs.cache-hit != 'true' run: npm ci + # ── Phase 2: 全量生产级断言检查(秒级瞬时恢复缓存,安全闭环) ────────────────── + lint: + name: Lint + runs-on: ubuntu-latest + needs: setup + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Restore Node Modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-release-v22-${{ hashFiles('**/package-lock.json') }} - name: Run ESLint run: npm run lint typecheck: name: TypeScript Check runs-on: ubuntu-latest + needs: setup steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' - - - name: Install dependencies - run: npm ci - + - name: Restore Node Modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-release-v22-${{ hashFiles('**/package-lock.json') }} - name: Run TypeScript type check run: npm run compile test: name: Unit Tests runs-on: ubuntu-latest + needs: setup steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' - - - name: Install dependencies - run: npm ci - + - name: Restore Node Modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-release-v22-${{ hashFiles('**/package-lock.json') }} - name: Run tests run: npm run test - # ── Phase 2: 打包 & 发布 ───────────────────────────────────────────── - release: - name: Package & Release + # ── Phase 3: 多端分布式高精打包(Compile & Upload Artifacts) ─────────────── + build-extension: + name: Package Extension runs-on: ubuntu-latest - needs: [lint, typecheck, test] + needs: [ lint, typecheck, test ] steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22' - cache: 'npm' + - name: Restore Node Modules + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-release-v22-${{ hashFiles('**/package-lock.json') }} - - name: Install dependencies - run: npm ci - - - name: Package Chrome extension - run: npm run zip - - - name: Package Firefox extension - run: npm run zip:firefox - - - name: Find zip artifacts - id: find_zips + # 执行 WXT 高阶打包压缩指令 + - name: Build and Zip Extension run: | - CHROME_ZIP=$(find .output -name "*.zip" | grep -v firefox | head -1) - FIREFOX_ZIP=$(find .output -name "*.zip" | grep firefox | head -1) - echo "chrome_zip=$CHROME_ZIP" >> "$GITHUB_OUTPUT" - echo "firefox_zip=$FIREFOX_ZIP" >> "$GITHUB_OUTPUT" - echo "Found Chrome zip: $CHROME_ZIP" - echo "Found Firefox zip: $FIREFOX_ZIP" + npm run zip + npm run zip:firefox + + # 💡 核心自愈补丁:显式将 .output 下打包出的真实生产绝对路径文件, + # 稳固地上存至 GitHub 的常驻产物箱中进行安全物理隔离,防范后期发布网络崩溃导致产物蒸发! + - name: Upload Extension Artifacts + uses: actions/upload-artifact@v4 + with: + name: extension-zips + path: | + .output/*.zip + retention-days: 7 + + # ── Phase 4: 独立中央签发发布(Atomic Release Publisher) ─────────────────── + release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: build-extension + steps: + - name: Checkout + uses: actions/checkout@v4 + + # 💡 独立下载打包完好的绝对产物包 + - name: Download Extension Artifacts + uses: actions/download-artifact@v4 + with: + name: extension-zips + path: release-artifacts - name: Extract version from tag id: version run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + # 💡 最终无风险原子级发布大礼包 - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: @@ -113,6 +156,6 @@ jobs: draft: false prerelease: ${{ contains(github.ref_name, '-') }} generate_release_notes: true + # 百分之百精准指向被下载下来的、毫无路径污染风险的 Zip 包实体 files: | - ${{ steps.find_zips.outputs.chrome_zip }} - ${{ steps.find_zips.outputs.firefox_zip }} + release-artifacts/*.zip \ No newline at end of file