-
Notifications
You must be signed in to change notification settings - Fork 38
215 lines (191 loc) · 8.23 KB
/
Copy pathaudience-bundle-size.yaml
File metadata and controls
215 lines (191 loc) · 8.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
name: Audience Bundle Size
on:
pull_request:
branches:
- "**"
# Do not add as a required check — PRs that don't touch these
# paths would be blocked forever (GitHub skips the check entirely
# instead of reporting it as passed).
paths:
- "packages/audience/sdk/**"
- "packages/audience/core/**"
- "packages/internal/metrics/**"
- "pnpm-lock.yaml"
- ".github/workflows/audience-bundle-size.yaml"
permissions: {}
concurrency:
group: audience-bundle-size-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
bundle-size:
name: Audience Bundle Size Check
runs-on: ubuntu-latest-4-cores
permissions:
pull-requests: write # post sticky bundle-size comment
contents: read
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.TS_IMMUTABLE_SDK_NX_TOKEN }}
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # pin@v6.0.3
with:
ref: ${{ github.event.pull_request.head.sha }}
# Full history needed — we check out the base commit later to measure its size.
fetch-depth: 0
persist-credentials: false
- name: Setup
uses: ./.github/actions/setup
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Read budget config
id: budget
shell: bash
run: |
BUDGET_DIR="packages/audience/sdk"
BUDGET_FILE="${BUDGET_DIR}/bundlebudget.json"
MAX_GZIP=$(jq -e '.budgets[0].maxSizeGzip | numbers' "$BUDGET_FILE") \
|| {
echo "::error file=${BUDGET_FILE}::.budgets[0].maxSizeGzip must be a number"
exit 1
}
WARN_GZIP=$(jq -e '.budgets[0].warnSizeGzip | numbers' "$BUDGET_FILE") \
|| {
echo "::error file=${BUDGET_FILE}::.budgets[0].warnSizeGzip must be a number"
exit 1
}
BUNDLE_REL=$(jq -er '.budgets[0].file | strings' "$BUDGET_FILE") \
|| {
echo "::error file=${BUDGET_FILE}::.budgets[0].file must be a string"
exit 1
}
{
echo "max_gzip=$MAX_GZIP"
echo "warn_gzip=$WARN_GZIP"
echo "bundle_path=${BUDGET_DIR}/${BUNDLE_REL}"
} >> "$GITHUB_OUTPUT"
- name: Build audience SDK (PR)
# The `...` suffix also builds audience-core and metrics, which get bundled in.
shell: bash
run: pnpm --filter @imtbl/audience... build
- name: Measure PR bundle size
id: pr_size
env:
BUNDLE: ${{ steps.budget.outputs.bundle_path }}
shell: bash
run: |
RAW_SIZE=$(stat --format=%s "$BUNDLE")
GZIP_SIZE=$(gzip -c "$BUNDLE" | wc -c)
echo "raw=$RAW_SIZE" >> "$GITHUB_OUTPUT"
echo "gzip=$GZIP_SIZE" >> "$GITHUB_OUTPUT"
echo "PR bundle: raw=${RAW_SIZE} bytes, gzip=${GZIP_SIZE} bytes"
- name: Build audience SDK (base) and measure
id: base_size
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
BUNDLE: ${{ steps.budget.outputs.bundle_path }}
shell: bash
run: |
if git checkout "$BASE_SHA" \
&& pnpm install --frozen-lockfile --ignore-scripts \
&& pnpm --filter @imtbl/audience... build \
&& [ -f "$BUNDLE" ]; then
RAW_SIZE=$(stat --format=%s "$BUNDLE")
GZIP_SIZE=$(gzip -c "$BUNDLE" | wc -c)
{
echo "ok=true"
echo "raw=$RAW_SIZE"
echo "gzip=$GZIP_SIZE"
} >> "$GITHUB_OUTPUT"
echo "Base bundle: ok=true, raw=${RAW_SIZE} bytes, gzip=${GZIP_SIZE} bytes"
else
echo "ok=false" >> "$GITHUB_OUTPUT"
echo "::warning::Base build at ${BASE_SHA} unavailable — delta vs ${BASE_REF} will be reported as n/a"
fi
# Switch back to the PR code so later steps run against the right version.
git checkout "$HEAD_SHA"
pnpm install --frozen-lockfile --ignore-scripts
- name: Evaluate bundle size
id: evaluate
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
PR_GZIP: ${{ steps.pr_size.outputs.gzip }}
PR_RAW: ${{ steps.pr_size.outputs.raw }}
BASE_GZIP: ${{ steps.base_size.outputs.gzip }}
BASE_RAW: ${{ steps.base_size.outputs.raw }}
BASE_OK: ${{ steps.base_size.outputs.ok }}
MAX_GZIP: ${{ steps.budget.outputs.max_gzip }}
WARN_GZIP: ${{ steps.budget.outputs.warn_gzip }}
shell: bash
run: |
BASE_SHA_SHORT="${BASE_SHA:0:7}"
if [ "$BASE_OK" = "true" ]; then
DELTA_GZIP=$((PR_GZIP - BASE_GZIP))
DELTA_RAW=$((PR_RAW - BASE_RAW))
if [ $DELTA_GZIP -gt 0 ]; then DELTA_GZIP_FMT="+${DELTA_GZIP} bytes"; else DELTA_GZIP_FMT="${DELTA_GZIP} bytes"; fi
if [ $DELTA_RAW -gt 0 ]; then DELTA_RAW_FMT="+${DELTA_RAW} bytes"; else DELTA_RAW_FMT="${DELTA_RAW} bytes"; fi
else
DELTA_GZIP_FMT="n/a (base build unavailable)"
DELTA_RAW_FMT="n/a"
fi
STATUS="pass"
STATUS_ICON="white_check_mark"
if [ "$PR_GZIP" -gt "$MAX_GZIP" ]; then
STATUS="fail"
STATUS_ICON="x"
elif [ "$PR_GZIP" -gt "$WARN_GZIP" ]; then
STATUS="warn"
STATUS_ICON="warning"
fi
PR_GZIP_KB=$(echo "scale=2; $PR_GZIP / 1024" | bc)
MAX_GZIP_KB=$(echo "scale=2; $MAX_GZIP / 1024" | bc)
WARN_GZIP_KB=$(echo "scale=2; $WARN_GZIP / 1024" | bc)
{
echo "## :${STATUS_ICON}: Audience Bundle Size — @imtbl/audience"
echo ""
echo "| Metric | Size | Delta vs \`${BASE_REF}\` (${BASE_SHA_SHORT}) |"
echo "|--------|------|---------------|"
echo "| **Gzipped** | ${PR_GZIP} bytes (${PR_GZIP_KB} KB) | ${DELTA_GZIP_FMT} |"
echo "| Raw (minified) | ${PR_RAW} bytes | ${DELTA_RAW_FMT} |"
echo ""
echo "**Budget:** ${MAX_GZIP_KB} KB gzipped (warn at ${WARN_GZIP_KB} KB)"
} > /tmp/comment-body.md
if [ "$BASE_OK" != "true" ]; then
echo "" >> /tmp/comment-body.md
echo "> :information_source: Base build at \`${BASE_SHA_SHORT}\` (\`${BASE_REF}\`) was unavailable; delta could not be computed. Gate still enforces the absolute budget." >> /tmp/comment-body.md
fi
if [ "$STATUS" = "warn" ]; then
echo "" >> /tmp/comment-body.md
echo "> :warning: **Approaching budget** — gzipped size exceeds ${WARN_GZIP_KB} KB warning threshold." >> /tmp/comment-body.md
fi
if [ "$STATUS" = "fail" ]; then
echo "" >> /tmp/comment-body.md
echo "> :x: **Over budget** — gzipped size exceeds ${MAX_GZIP_KB} KB limit. Reduce bundle size before merging." >> /tmp/comment-body.md
fi
echo "status=$STATUS" >> "$GITHUB_OUTPUT"
EOF_MARKER=$(head -c 20 /dev/urandom | base64 | tr -d '/+=' | head -c 20)
{
echo "comment<<${EOF_MARKER}"
cat /tmp/comment-body.md
echo "${EOF_MARKER}"
} >> "$GITHUB_OUTPUT"
cat /tmp/comment-body.md >> "$GITHUB_STEP_SUMMARY"
- name: Post PR comment
# Without this guard, fork PRs fail the whole job on a permission error.
if: github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/actions/sticky-comment
with:
header: audience-bundle-size
message: ${{ steps.evaluate.outputs.comment }}
- name: Fail if over budget
if: steps.evaluate.outputs.status == 'fail'
env:
PR_GZIP: ${{ steps.pr_size.outputs.gzip }}
MAX_GZIP: ${{ steps.budget.outputs.max_gzip }}
shell: bash
run: |
echo "::error::Audience bundle gzipped size (${PR_GZIP} bytes) exceeds budget (${MAX_GZIP} bytes)"
exit 1