Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/actions/binary-limit/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,27 @@ inputs:
description: "the increase size limit in bytes, default is 50kb"
default: "51200"
required: false
platform:
description: "target triple name used to locate the binary"
default: "x86_64-unknown-linux-gnu"
required: false

outputs:
result:
description: "JSON encoded size report"
value: ${{ steps.size-report.outputs.result }}

runs:
using: composite

steps:
- name: GitHub Script
id: size-report
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
with:
script: |
const limit = parseInt("${{ inputs.size-threshold }}") || 51200;
const platform = inputs.platform;
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The platform input should be accessed using GitHub Actions expression syntax. Line 30 attempts to access inputs.platform directly in JavaScript, but inputs is not available in the script context. It should be "${{ inputs.platform }}" to match the pattern used on line 29 for size-threshold.

Suggested change
const platform = inputs.platform;
const platform = "${{ inputs.platform }}";

Copilot uses AI. Check for mistakes.
const action = require("./.github/actions/binary-limit/binary-limit-script.js");
await action({github, context, limit});
const result = await action({github, context, limit, platform});
core.setOutput("result", JSON.stringify(result));
101 changes: 69 additions & 32 deletions .github/actions/binary-limit/binary-limit-script.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
const fs = require("node:fs");

const SIZE_LIMIT_HEADING = "## 📦 Binary Size-limit";
const DEFAULT_PLATFORM = "x86_64-unknown-linux-gnu";

const BINARY_PATHS = {
"x86_64-unknown-linux-gnu": "rspack.linux-x64-gnu.node",
"aarch64-apple-darwin": "rspack.darwin-arm64.node",
"x86_64-pc-windows-msvc": "rspack.win32-x64-msvc.node"
};

const PLATFORM_LABELS = {
"x86_64-unknown-linux-gnu": "Linux x64 (glibc)",
"aarch64-apple-darwin": "macOS arm64",
"x86_64-pc-windows-msvc": "Windows x64"
};

/**
* @param {import("@octokit/rest")} github
* @param {Number} limit
* @param {{ github: import('@octokit/rest'), context: any, limit: number, platform?: string }} options
*/
module.exports = async function action({ github, context, limit }) {
async function run({ github, context, limit, platform }) {
const target = platform || DEFAULT_PLATFORM;
const commits = await github.rest.repos.listCommits({
owner: context.repo.owner,
repo: context.repo.repo,
Expand All @@ -18,10 +33,13 @@ module.exports = async function action({ github, context, limit }) {
console.log(commit.sha);
try {
const data = await fetchDataBySha(commit.sha);
if (data?.size) {
const size = data?.sizes?.[target] ?? data?.size;
if (typeof size === "number") {
baseCommit = commit;
baseSize = data.size;
console.log(`Commit ${commit.sha} has binary size: ${data.size}`);
baseSize = size;
console.log(
`Commit ${commit.sha} has binary size (${target}): ${size}`
);
break;
}
} catch (e) {
Expand All @@ -35,48 +53,49 @@ module.exports = async function action({ github, context, limit }) {
throw new Error(error);
}

const headSize = fs.statSync(
"./crates/node_binding/rspack.linux-x64-gnu.node"
).size;
const file = getBinaryPath(target);
console.log(`Checking binary size for ${file}`);
const headSize = fs.statSync(file).size;

console.log(`Base commit size: ${baseSize}`);
console.log(`Head commit size: ${headSize}`);

const comment = compareBinarySize(headSize, baseSize, context, baseCommit);

try {
await commentToPullRequest(github, context, comment);
} catch (e) {
console.error("Failed to comment on pull request:", e);
}
console.log(`Base commit size (${target}): ${baseSize}`);
console.log(`Head commit size (${target}): ${headSize}`);

const increasedSize = headSize - baseSize;
if (increasedSize > limit) {
throw new Error(
`Binary size increased by ${increasedSize} bytes, exceeding the limit of ${limit} bytes`
);
}
};
return {
platform: target,
baseSize,
headSize,
increasedSize,
exceeded: increasedSize > limit,
comment: compareBinarySize(headSize, baseSize, context, baseCommit)
};
}

module.exports = run;
module.exports.commentToPullRequest = commentToPullRequest;
module.exports.formatReport = formatReport;
module.exports.getBinaryPath = getBinaryPath;
module.exports.SIZE_LIMIT_HEADING = SIZE_LIMIT_HEADING;

async function commentToPullRequest(github, context, comment) {
async function commentToPullRequest(github, context, body) {
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.number
});

const prevComment = comments.filter(
const prevComment = comments.find(
comment =>
comment.user.login === "github-actions[bot]" &&
comment.body.startsWith(SIZE_LIMIT_HEADING)
)[0];
);

if (prevComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: prevComment.id,
body: `${SIZE_LIMIT_HEADING}\n${comment}`
body
});
return;
}
Expand All @@ -85,8 +104,19 @@ async function commentToPullRequest(github, context, comment) {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.number,
body: `${SIZE_LIMIT_HEADING}\n${comment}`
body
});
}

function formatReport(entries) {
const ordered = [...entries].sort((a, b) =>
a.platform.localeCompare(b.platform)
);
const sections = ordered.map(entry => {
const title = PLATFORM_LABELS[entry.platform] || entry.platform;
return `### ${title}\n${entry.comment}`;
});
return `${SIZE_LIMIT_HEADING}\n\n${sections.join("\n\n")}`.trim();
}

function fetchDataBySha(sha) {
Expand All @@ -95,8 +125,6 @@ function fetchDataBySha(sha) {
return fetch(dataUrl).then(res => res.json());
}

const SIZE_LIMIT_HEADING = "## 📦 Binary Size-limit";

const DATA_URL_BASE =
"https://raw.githubusercontent.com/web-infra-dev/rspack-ecosystem-benchmark/data";

Expand All @@ -118,6 +146,15 @@ function compareBinarySize(headSize, baseSize, context, baseCommit) {
return `${info}🙈 Size remains the same at ${toHumanReadable(headSize)}`;
}

function getBinaryPath(platform) {
const target = platform || DEFAULT_PLATFORM;
const filename = BINARY_PATHS[target];
if (!filename) {
throw new Error(`Unsupported platform: ${target}`);
}
return `./crates/node_binding/${filename}`;
}

function toHumanReadable(size) {
if (size < 1024) {
return `${size}bytes`;
Expand Down
85 changes: 78 additions & 7 deletions .github/workflows/size-limit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ permissions:
jobs:
size-limit:
name: Binding Size Limit
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
id: linux
- target: aarch64-apple-darwin
id: mac
- target: x86_64-pc-windows-msvc
id: win
runs-on: ${{ fromJSON(vars.LINUX_SELF_HOSTED_RUNNER_LABELS || '"ubuntu-22.04"') }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
Expand All @@ -27,13 +37,11 @@ jobs:
- name: Install Rust Toolchain
uses: ./.github/actions/rustup
with:
key: x86_64-unknown-linux-gnu-release
# don't need use cache in self-hosted windows; benefits of build with cargo build are wasted by cache restore
key: ${{ matrix.target }}-release
save-if: ${{ runner.environment != 'self-hosted' || runner.os != 'Windows' }}

# setup rust target for native runner
- name: Setup Rust Target
run: rustup target add x86_64-unknown-linux-gnu
run: rustup target add ${{ matrix.target }}

- name: Run Cargo codegen
run: cargo codegen
Expand All @@ -50,13 +58,76 @@ jobs:
with:
tool-cache: fals

- name: Build x86_64-unknown-linux-gnu native
- name: Build ${{ matrix.target }} native
run: |
rustup target add x86_64-unknown-linux-gnu
RUST_TARGET=x86_64-unknown-linux-gnu pnpm build:binding:release
rustup target add ${{ matrix.target }}
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant rustup target add command. This target was already added in the "Setup Rust Target" step at line 47. The duplicate command on line 59 should be removed.

Suggested change
rustup target add ${{ matrix.target }}

Copilot uses AI. Check for mistakes.
RUST_TARGET=${{ matrix.target }} pnpm build:binding:release

- name: Binary Size-limit
id: size
uses: ./.github/actions/binary-limit
with:
# 50k 50*1024
size-threshold: 51200
platform: ${{ matrix.target }}

- name: Save size result
if: steps.size.outputs.result != ''
shell: bash
env:
RESULT: ${{ steps.size.outputs.result }}
run: |
printf '%s' "$RESULT" > size-result.json

- name: Upload size result
if: steps.size.outputs.result != ''
uses: actions/upload-artifact@v4
with:
name: binary-size-${{ matrix.id }}
path: size-result.json
if-no-files-found: error

gather-results:
name: Gather Binary Size Results
needs: size-limit
if: always()
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Download size reports
uses: actions/[email protected]
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent action version format. The action version should be @v4.1.7 (with v prefix) to match the convention used elsewhere in the repository (e.g., line 21 in .github/actions/artifact/download/action.yml).

Suggested change
uses: actions/download-artifact@4.1.7
uses: actions/download-artifact@v4.1.7

Copilot uses AI. Check for mistakes.
with:
pattern: binary-size-*
merge-multiple: true
path: size-results
if-no-files-found: error

- name: Post combined report
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
env:
RESULTS_DIR: size-results
with:
script: |
const fs = require("node:fs");
const path = require("node:path");
const action = require("./.github/actions/binary-limit/binary-limit-script.js");
const dir = process.env.RESULTS_DIR;
if (!fs.existsSync(dir)) {
core.info("No size reports found");
return;
}
const files = fs.readdirSync(dir).filter(name => name.endsWith(".json"));
if (!files.length) {
core.info("No size reports to process");
return;
}
const entries = files.map(file => {
const raw = fs.readFileSync(path.join(dir, file), "utf8");
return JSON.parse(raw);
});
const body = action.formatReport(entries);
await action.commentToPullRequest(github, context, body);
if (entries.some(entry => entry.exceeded)) {
core.setFailed("Binary size limit exceeded");
}
4 changes: 3 additions & 1 deletion crates/node_binding/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ async function build() {
}
if (values.profile === "release") {
features.push("info-level");
rustflags.push("-Cforce-unwind-tables=no");
if (process.env.RUST_TARGET && !process.env.RUST_TARGET.startsWith("windows-msvc")) {
rustflags.push("-Cforce-unwind-tables=no");
}
}
if (features.length) {
args.push("--features " + features.join(","));
Expand Down
Loading