Skip to content

Commit 49a5d90

Browse files
authored
chore: CI enable binary size limit (#10875)
* chore: use benchmark size data * refactor: extract workflow call workflow
1 parent 0932978 commit 49a5d90

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Binary Size Limit
2+
3+
description: Compare binary size with default
4+
5+
inputs:
6+
percentage-threshold:
7+
description: "the"
8+
default: "5"
9+
required: false
10+
11+
runs:
12+
using: composite
13+
14+
steps:
15+
- name: GitHub Script
16+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
17+
with:
18+
script: |
19+
const action = require("./.github/actions/binary-limit/binary-limit-script.js");
20+
await action({github, context});
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
const fs = require("node:fs");
2+
3+
/**
4+
* @param {import("@octokit/rest")} github
5+
*/
6+
module.exports = async function action({ github, context }) {
7+
const commits = await github.rest.repos.listCommits({
8+
owner: context.repo.owner,
9+
repo: context.repo.repo,
10+
per_page: 30
11+
});
12+
13+
let baseSize = 0;
14+
let baseCommit = null;
15+
16+
for (const commit of commits.data) {
17+
console.log(commit.sha);
18+
try {
19+
const data = await fetchDataBySha(commit.sha);
20+
if (data?.size) {
21+
baseCommit = commit;
22+
baseSize = data.size;
23+
console.log(`Commit ${commit.sha} has binary size: ${data.size}`);
24+
break;
25+
}
26+
} catch (e) {
27+
console.log(e);
28+
}
29+
}
30+
31+
if (!baseCommit) {
32+
const error = `No base binary size found within ${commits.data.length} commits`;
33+
console.log(error);
34+
throw new Error(error);
35+
}
36+
37+
const headSize = fs.statSync(
38+
"./crates/node_binding/rspack.linux-x64-gnu.node"
39+
).size;
40+
41+
const comment = compareBinarySize(headSize, baseSize, baseCommit);
42+
43+
await commentToPullRequest(github, context, comment);
44+
};
45+
46+
async function commentToPullRequest(github, context, comment) {
47+
const { data: comments } = await github.rest.issues.listComments({
48+
owner: context.repo.owner,
49+
repo: context.repo.repo,
50+
issue_number: context.payload.number
51+
});
52+
53+
const prevComment = comments.filter(
54+
comment =>
55+
comment.user.login === "github-actions[bot]" &&
56+
comment.body.startsWith(SIZE_LIMIT_HEADING)
57+
)[0];
58+
59+
if (prevComment) {
60+
await github.rest.issues.updateComment({
61+
owner: context.repo.owner,
62+
repo: context.repo.repo,
63+
comment_id: prevComment.id,
64+
body: `${SIZE_LIMIT_HEADING}\n${comment}`
65+
});
66+
return;
67+
}
68+
69+
await github.rest.issues.createComment({
70+
owner: context.repo.owner,
71+
repo: context.repo.repo,
72+
issue_number: context.payload.number,
73+
body: `${SIZE_LIMIT_HEADING}\n${comment}`
74+
});
75+
}
76+
77+
function fetchDataBySha(sha) {
78+
const dataUrl = `${DATA_URL_BASE}/commits/${sha.slice(0, 2)}/${sha.slice(2)}/rspack-build.json`;
79+
console.log("fetching", dataUrl, "...");
80+
return fetch(dataUrl).then(res => res.json());
81+
}
82+
83+
const SIZE_LIMIT_HEADING = "## 📦 Binary Size-limit";
84+
85+
const DATA_URL_BASE =
86+
"https://raw.githubusercontent.com/web-infra-dev/rspack-ecosystem-benchmark/data";
87+
88+
function compareBinarySize(headSize, baseSize, baseCommit) {
89+
const message = baseCommit.commit.message.split("\n")[0];
90+
const author = baseCommit.commit.author.name;
91+
92+
const info = `> Comparing binary size with Commit: [${message} by ${author}](${baseCommit.html_url})\n\n`;
93+
94+
const diff = headSize - baseSize;
95+
const percentage = (Math.abs(diff / baseSize) * 100).toFixed(2);
96+
if (diff > 0) {
97+
return `${info}❌ Size increased by ${toHumanReadable(diff)} from ${toHumanReadable(baseSize)} to ${toHumanReadable(headSize)} (⬆️${percentage}%)`;
98+
}
99+
if (diff < 0) {
100+
return `${info}🎉 Size decreased by ${toHumanReadable(-diff)} from ${toHumanReadable(baseSize)} to ${toHumanReadable(headSize)} (⬇️${percentage}%)`;
101+
}
102+
return `${info}🙈 Size remains the same at ${toHumanReadable(headSize)}`;
103+
}
104+
105+
function toHumanReadable(size) {
106+
if (size < 1024) {
107+
return `${size}bytes`;
108+
}
109+
if (size < 1024 * 1024) {
110+
return `${(size / 1024).toFixed(2)}KB`;
111+
}
112+
return `${(size / 1024 / 1024).toFixed(2)}MB`;
113+
}

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ concurrency:
2828
permissions:
2929
# Allow commenting on issues for `reusable-build.yml`
3030
issues: write
31+
# Allow commenting on pull requests for `size-limit.yml`
32+
pull-requests: write
3133

3234
jobs:
3335
check-changed:
@@ -138,6 +140,12 @@ jobs:
138140
- name: No check to Run test
139141
run: echo "Success"
140142

143+
size-limit:
144+
name: Binary Size Limit
145+
needs: [check-changed]
146+
if: ${{ needs.check-changed.outputs.code_changed == 'true' && github.event_name == 'pull_request' }}
147+
uses: ./.github/workflows/size-limit.yml
148+
141149
# TODO: enable it after self hosted runners are ready
142150
# pkg-preview:
143151
# name: Pkg Preview

.github/workflows/size-limit.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Binary Size Limit
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
# Allow commenting on Pull Requests
8+
pull-requests: write
9+
10+
jobs:
11+
size-limit:
12+
name: Binding Size Limit
13+
runs-on: ${{ fromJSON(vars.LINUX_SELF_HOSTED_RUNNER_LABELS || '"ubuntu-22.04"') }}
14+
steps:
15+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
16+
17+
- name: Pnpm Setup
18+
uses: ./.github/actions/pnpm/setup
19+
20+
- name: Install Binding Dependencies
21+
uses: ./.github/actions/pnpm/install-binding-dependencies
22+
with:
23+
# binding dependencies so small that we don't need to cache them
24+
# a fresh new installation takes about 5s
25+
save-if: false
26+
27+
- name: Install Rust Toolchain
28+
uses: ./.github/actions/rustup
29+
with:
30+
key: x86_64-unknown-linux-gnu-release
31+
# don't need use cache in self-hosted windows; benefits of build with cargo build are wasted by cache restore
32+
save-if: ${{ runner.environment != 'self-hosted' || runner.os != 'Windows' }}
33+
34+
# setup rust target for native runner
35+
- name: Setup Rust Target
36+
run: rustup target add x86_64-unknown-linux-gnu
37+
38+
- name: Trim paths
39+
run: |
40+
echo $'\n' >> .cargo/config.toml
41+
echo 'trim-paths = true' >> .cargo/config.toml
42+
43+
# Fix: Resolve disk space error "ENOSPC: no space left on device" on GitHub Actions runners
44+
- name: Free disk cache
45+
if: runner.environment == 'github-hosted'
46+
uses: xc2/free-disk-space@fbe203b3788f2bebe2c835a15925da303eaa5efe # v1.0.0
47+
with:
48+
tool-cache: fals
49+
50+
- name: Build x86_64-unknown-linux-gnu native
51+
run: |
52+
unset CC_x86_64_unknown_linux_gnu && unset CC # for jemallocator to compile
53+
rustup target add x86_64-unknown-linux-gnu
54+
RUST_TARGET=x86_64-unknown-linux-gnu pnpm build:binding:release
55+
56+
- name: Binary Size-limit
57+
uses: ./.github/actions/binary-limit

0 commit comments

Comments
 (0)