chore(release): v0.3.2 #95
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: Bundle Analysis | |
| on: | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'src/**' | |
| - 'package.json' | |
| - 'pnpm-lock.yaml' | |
| - 'tsconfig.json' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| analyze: | |
| name: Analyze Bundle Size | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout PR | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Checkout base | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| ref: ${{ github.base_ref }} | |
| path: base | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6 | |
| with: | |
| node-version: '20' | |
| cache: 'pnpm' | |
| - name: Install and build PR | |
| run: | | |
| set -euo pipefail | |
| pnpm install --frozen-lockfile | |
| if ! pnpm build; then | |
| echo "::error::PR build failed" | |
| exit 1 | |
| fi | |
| if [ ! -d "dist" ]; then | |
| echo "::error::dist directory not found after build" | |
| exit 1 | |
| fi | |
| - name: Install and build base | |
| run: | | |
| set -euo pipefail | |
| cd base | |
| # For base comparison, don't use frozen-lockfile as it may be out of sync | |
| if [ -f "pnpm-lock.yaml" ]; then | |
| pnpm install --no-frozen-lockfile | |
| elif [ -f "package-lock.json" ]; then | |
| npm ci | |
| else | |
| pnpm install | |
| fi | |
| if ! pnpm build 2>/dev/null && ! npm run build 2>/dev/null; then | |
| echo "::error::Base build failed" | |
| exit 1 | |
| fi | |
| if [ ! -d "dist" ]; then | |
| echo "::error::base/dist directory not found after build" | |
| exit 1 | |
| fi | |
| - name: Compare bundle sizes | |
| id: compare | |
| run: | | |
| set -euo pipefail | |
| # Get PR bundle size | |
| PR_SIZE=$(du -sb dist | cut -f1) | |
| PR_SIZE_KB=$(echo "scale=2; $PR_SIZE / 1024" | bc) | |
| # Get base bundle size | |
| BASE_SIZE=$(du -sb base/dist | cut -f1) | |
| BASE_SIZE_KB=$(echo "scale=2; $BASE_SIZE / 1024" | bc) | |
| # Calculate difference with divide-by-zero protection | |
| DIFF=$((PR_SIZE - BASE_SIZE)) | |
| DIFF_KB=$(echo "scale=2; $DIFF / 1024" | bc) | |
| if [ "$BASE_SIZE" -eq 0 ]; then | |
| DIFF_PERCENT="N/A" | |
| else | |
| DIFF_PERCENT=$(echo "scale=2; ($DIFF / $BASE_SIZE) * 100" | bc 2>/dev/null || echo "0") | |
| fi | |
| # Get bundle breakdown for PR comment | |
| BUNDLE_BREAKDOWN=$(du -sh dist/* 2>/dev/null || echo "No files in dist/") | |
| echo "pr_size=$PR_SIZE_KB" >> $GITHUB_OUTPUT | |
| echo "base_size=$BASE_SIZE_KB" >> $GITHUB_OUTPUT | |
| echo "diff=$DIFF_KB" >> $GITHUB_OUTPUT | |
| echo "diff_percent=$DIFF_PERCENT" >> $GITHUB_OUTPUT | |
| # Use heredoc for multiline output | |
| { | |
| echo 'bundle_breakdown<<EOF' | |
| echo "$BUNDLE_BREAKDOWN" | |
| echo 'EOF' | |
| } >> $GITHUB_OUTPUT | |
| # Determine status emoji | |
| if [ "$DIFF" -gt 51200 ]; then | |
| echo "status=:warning:" >> $GITHUB_OUTPUT | |
| elif [ "$DIFF" -lt 0 ]; then | |
| echo "status=:white_check_mark:" >> $GITHUB_OUTPUT | |
| else | |
| echo "status=:heavy_check_mark:" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Comment on PR | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const prSize = '${{ steps.compare.outputs.pr_size }}'; | |
| const baseSize = '${{ steps.compare.outputs.base_size }}'; | |
| const diff = '${{ steps.compare.outputs.diff }}'; | |
| const diffPercent = '${{ steps.compare.outputs.diff_percent }}'; | |
| const status = '${{ steps.compare.outputs.status }}'; | |
| const bundleBreakdown = `${{ steps.compare.outputs.bundle_breakdown }}`; | |
| const table = [ | |
| '| Metric | Value |', | |
| '|--------|-------|', | |
| `| **Base** | ${baseSize} KB |`, | |
| `| **PR** | ${prSize} KB |`, | |
| `| **Diff** | ${diff} KB (${diffPercent}%) |` | |
| ].join('\n'); | |
| const body = [ | |
| `## ${status} Bundle Size Analysis`, | |
| '', | |
| table, | |
| '', | |
| '<details>', | |
| '<summary>Bundle breakdown</summary>', | |
| '', | |
| '```', | |
| bundleBreakdown, | |
| '```', | |
| '', | |
| '</details>' | |
| ].join('\n'); | |
| // Find existing comment | |
| const comments = await github.rest.issues.listComments({ | |
| owner, | |
| repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.data.find(c => | |
| c.user.type === 'Bot' && c.body.includes('Bundle Size Analysis') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: botComment.id, | |
| body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: context.issue.number, | |
| body | |
| }); | |
| } |