Skip to content

Commit a14f75e

Browse files
committed
Address review comments
1 parent 2c8faa5 commit a14f75e

4 files changed

Lines changed: 67 additions & 61 deletions

File tree

.github/workflows/pr-checks.yml

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ jobs:
7373

7474
# These checks do not need to be run as part of the same matrix that we use for the `unit-tests`
7575
# job.
76-
pr-checks:
77-
name: PR Checks
76+
other-checks:
77+
name: Other checks
7878
if: github.triggering_actor != 'dependabot[bot]'
7979
permissions:
8080
contents: read
@@ -96,12 +96,15 @@ jobs:
9696
cache: 'npm'
9797

9898
- name: Install dependencies
99+
id: install-deps
99100
run: npm ci
100101

101102
- name: Verify PR checks up to date
103+
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
102104
run: .github/workflows/script/verify-pr-checks.sh
103105

104106
- name: Run pr-checks tests
107+
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
105108
working-directory: pr-checks
106109
run: npx tsx --test
107110

@@ -117,6 +120,7 @@ jobs:
117120
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
118121
119122
- name: Fetch base commit
123+
id: fetch-base
120124
# Forks and Dependabot PRs don't have permission to write comments, so skip the repo size
121125
# check in those cases.
122126
if: >-
@@ -125,29 +129,28 @@ jobs:
125129
github.event.pull_request.user.login != 'dependabot[bot]'
126130
env:
127131
BASE_SHA: ${{ github.event.pull_request.base.sha }}
128-
run: git fetch --no-tags --depth=1 origin "$BASE_SHA"
132+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
133+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
134+
run: |
135+
# Compare against the merge base so the size delta reflects only the commits actually
136+
# added by this PR, ignoring any changes that have landed on the base branch since the
137+
# PR branched off.
138+
merge_base=$(gh api "repos/$GITHUB_REPOSITORY/compare/$BASE_SHA...$HEAD_SHA" --jq '.merge_base_commit.sha')
139+
echo "merge_base=$merge_base" >> "$GITHUB_OUTPUT"
140+
git fetch --no-tags --depth=1 origin "$merge_base" "$HEAD_SHA"
129141
130142
- name: Check repo size
131-
# Forks and Dependabot PRs don't have permission to write comments, so skip the repo size
132-
# check in those cases.
133-
if: >-
134-
github.event_name == 'pull_request' &&
135-
github.event.pull_request.head.repo.full_name == github.repository &&
136-
github.event.pull_request.user.login != 'dependabot[bot]'
143+
if: steps.fetch-base.outcome == 'success'
137144
working-directory: pr-checks
138145
env:
139146
BASE_REF: ${{ github.event.pull_request.base.ref }}
140-
BASE_SHA: ${{ github.event.pull_request.base.sha }}
147+
BASE_SHA: ${{ steps.fetch-base.outputs.merge_base }}
148+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
141149
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
142150
run: npx tsx check-repo-size.ts --output-dir "$RUNNER_TEMP/repo-size"
143151

144152
- name: Upload repo size comment
145-
# Forks and Dependabot PRs don't have permission to write comments, so skip the repo size
146-
# check in those cases.
147-
if: >-
148-
github.event_name == 'pull_request' &&
149-
github.event.pull_request.head.repo.full_name == github.repository &&
150-
github.event.pull_request.user.login != 'dependabot[bot]'
153+
if: steps.fetch-base.outcome == 'success'
151154
uses: actions/upload-artifact@v7
152155
with:
153156
name: repo-size-comment
@@ -176,14 +179,14 @@ jobs:
176179
177180
post-repo-size-comment:
178181
name: Post repo size comment
179-
needs: pr-checks
182+
needs: other-checks
180183
# Keep write permissions isolated from the job that checks out and tests PR code. This job only
181184
# posts the candidate comment body produced by the read-only `pr-checks` job.
182185
if: >-
183186
github.event_name == 'pull_request' &&
184187
github.event.pull_request.head.repo.full_name == github.repository &&
185188
github.event.pull_request.user.login != 'dependabot[bot]' &&
186-
needs.pr-checks.result == 'success'
189+
needs.other-checks.result == 'success'
187190
permissions:
188191
contents: read
189192
pull-requests: write
@@ -205,7 +208,6 @@ jobs:
205208
env:
206209
COMMENT_MARKER: "<!-- repo-size-diff-bot -->"
207210
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
208-
GITHUB_REPOSITORY: ${{ github.repository }}
209211
PR_NUMBER: ${{ github.event.pull_request.number }}
210212
run: |
211213
significant=$(jq -r '.significant' repo-size-comment/metadata.json)

pr-checks/check-repo-size.test.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,18 @@ import {
2525

2626
describe("formatBytes", async () => {
2727
const cases: Array<[number, boolean, string]> = [
28-
// Unsigned: bytes / KiB / MiB boundaries.
29-
[0, false, "0 B"],
30-
[1, false, "1 B"],
31-
[1023, false, "1023 B"],
28+
// Unsigned values, including sub-KiB amounts which round to 0.00.
29+
[0, false, "0.00 KiB"],
30+
[512, false, "0.50 KiB"],
3231
[1024, false, "1.00 KiB"],
33-
[2048, false, "2.00 KiB"],
34-
[1024 * 1024 - 1, false, "1024.00 KiB"],
35-
[1024 * 1024, false, "1.00 MiB"],
36-
[2.5 * 1024 * 1024, false, "2.50 MiB"],
32+
[1024 * 1024, false, "1024.00 KiB"],
33+
[2 * 1024 * 1024, false, "2048.00 KiB"],
3734
// Negative values always use a leading minus.
38-
[-512, false, "-512 B"],
39-
[-2048, false, "-2.00 KiB"],
40-
[-2 * 1024 * 1024, false, "-2.00 MiB"],
35+
[-2 * 1024 * 1024, false, "-2048.00 KiB"],
4136
// signed=true prepends a + to non-negative values.
42-
[0, true, "+0 B"],
43-
[512, true, "+512 B"],
44-
[2048, true, "+2.00 KiB"],
45-
[-512, true, "-512 B"],
37+
[0, true, "+0.00 KiB"],
38+
[2 * 1024 * 1024, true, "+2048.00 KiB"],
39+
[-2 * 1024 * 1024, true, "-2048.00 KiB"],
4640
];
4741
for (const [bytes, signed, expected] of cases) {
4842
await it(`formats ${bytes} (signed=${signed}) as ${expected}`, () => {
@@ -94,8 +88,8 @@ describe("buildCommentBody", async () => {
9488
});
9589

9690
assert.match(body, new RegExp(`^${escapeRegExp(COMMENT_MARKER)}`));
97-
assert.match(body, /Base \(`main`\) \| 1\.91 MiB \(2000000 bytes\)/);
98-
assert.match(body, /This PR \| 2\.19 MiB \(2300000 bytes\)/);
91+
assert.match(body, /Base \(`main`\) \| 1953\.13 KiB \(2000000 bytes\)/);
92+
assert.match(body, /This PR \| 2246\.09 KiB \(2300000 bytes\)/);
9993
assert.match(
10094
body,
10195
/\*\*Delta\*\* \| \*\*\+292\.97 KiB \(\+300000 bytes, \+15\.00%\)\*\*/,
@@ -118,7 +112,7 @@ describe("buildCommentBody", async () => {
118112
});
119113

120114
describe("readArgs", async () => {
121-
await it("defaults the base ref for local runs", () => {
115+
await it("defaults the base ref and head commit for local runs", () => {
122116
const originalEnv = process.env;
123117
const originalArgv = process.argv;
124118

@@ -130,6 +124,7 @@ describe("readArgs", async () => {
130124

131125
assert.equal(args.baseRef, DEFAULT_BASE_REF);
132126
assert.equal(args.baseCommitish, `origin/${DEFAULT_BASE_REF}`);
127+
assert.equal(args.headCommitish, "HEAD");
133128
assert.equal(args.outputDir, "/tmp/out");
134129
assert.equal(args.runUrl, undefined);
135130
} finally {
@@ -138,14 +133,15 @@ describe("readArgs", async () => {
138133
}
139134
});
140135

141-
await it("uses the base SHA when provided by the workflow", () => {
136+
await it("uses the base and head SHAs when provided by the workflow", () => {
142137
const originalEnv = process.env;
143138
const originalArgv = process.argv;
144139

145140
try {
146141
process.env = {
147142
BASE_REF: "main",
148143
BASE_SHA: "abc123",
144+
HEAD_SHA: "def456",
149145
RUN_URL: "https://example.test/run",
150146
};
151147
process.argv = ["node", "check-repo-size.ts", "--output-dir", "/tmp/out"];
@@ -154,6 +150,7 @@ describe("readArgs", async () => {
154150

155151
assert.equal(args.baseRef, "main");
156152
assert.equal(args.baseCommitish, "abc123");
153+
assert.equal(args.headCommitish, "def456");
157154
assert.equal(args.outputDir, "/tmp/out");
158155
assert.equal(args.runUrl, "https://example.test/run");
159156
} finally {

pr-checks/check-repo-size.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import * as fs from "node:fs";
1414
import * as path from "node:path";
1515
import { parseArgs } from "node:util";
1616

17+
import { getErrorMessage } from "../src/util";
18+
19+
import { REPO_ROOT } from "./config";
20+
1721
/** Hidden marker used to find the existing sticky comment on a PR. */
1822
export const COMMENT_MARKER = "<!-- repo-size-diff-bot -->";
1923

@@ -62,15 +66,13 @@ export async function measureArchiveSize(
6266
}
6367

6468
/**
65-
* Format a byte count into a human-readable string with binary units. If `signed` is true, a
66-
* leading `+` is prepended for non-negative values so gains and losses are visually distinct.
69+
* Format a byte count as KiB. If `signed` is true, a leading `+` is prepended for non-negative
70+
* values so gains and losses are visually distinct.
6771
*/
6872
export function formatBytes(bytes: number, signed = false): string {
6973
const sign = bytes < 0 ? "-" : signed ? "+" : "";
70-
const abs = Math.abs(bytes);
71-
if (abs < 1024) return `${sign}${abs} B`;
72-
if (abs < 1024 * 1024) return `${sign}${(abs / 1024).toFixed(2)} KiB`;
73-
return `${sign}${(abs / 1024 / 1024).toFixed(2)} MiB`;
74+
const kib = Math.abs(bytes) / 1024;
75+
return `${sign}${kib.toFixed(2)} KiB`;
7476
}
7577

7678
/** Format a fraction as a signed percentage with 2 decimal places. */
@@ -131,6 +133,8 @@ interface MainArgs {
131133
baseRef: string;
132134
/** Base commit-ish to archive. Defaults to `origin/<baseRef>` for local runs. */
133135
baseCommitish: string;
136+
/** Head commit-ish to archive. Defaults to `HEAD` for local runs. */
137+
headCommitish: string;
134138
/** Optional URL of the workflow run, surfaced in the comment footer. */
135139
runUrl?: string;
136140
/** Directory where `body.md` and `metadata.json` are written. */
@@ -152,10 +156,12 @@ export function readArgs(): MainArgs {
152156

153157
const baseRef = process.env.BASE_REF ?? DEFAULT_BASE_REF;
154158
const baseCommitish = process.env.BASE_SHA ?? `origin/${baseRef}`;
159+
const headCommitish = process.env.HEAD_SHA ?? "HEAD";
155160

156161
return {
157162
baseRef,
158163
baseCommitish,
164+
headCommitish,
159165
runUrl: process.env.RUN_URL,
160166
outputDir,
161167
};
@@ -164,16 +170,12 @@ export function readArgs(): MainArgs {
164170
async function main(): Promise<number> {
165171
const args = readArgs();
166172

167-
// The script lives at `<repoRoot>/pr-checks/check-repo-size.ts`, so the repo root is the parent
168-
// directory.
169-
const repoRoot = path.resolve(__dirname, "..");
170-
171173
console.log(`Measuring base archive size for ${args.baseCommitish}...`);
172-
const baseSize = await measureArchiveSize(args.baseCommitish, repoRoot);
174+
const baseSize = await measureArchiveSize(args.baseCommitish, REPO_ROOT);
173175
console.log(` ${baseSize} bytes`);
174176

175-
console.log("Measuring PR archive size for HEAD...");
176-
const prSize = await measureArchiveSize("HEAD", repoRoot);
177+
console.log(`Measuring PR archive size for ${args.headCommitish}...`);
178+
const prSize = await measureArchiveSize(args.headCommitish, REPO_ROOT);
177179
console.log(` ${prSize} bytes`);
178180

179181
const delta = prSize - baseSize;
@@ -209,13 +211,15 @@ async function main(): Promise<number> {
209211
return 0;
210212
}
211213

214+
async function run(): Promise<void> {
215+
try {
216+
process.exit(await main());
217+
} catch (err) {
218+
console.error(getErrorMessage(err));
219+
process.exit(1);
220+
}
221+
}
222+
212223
if (require.main === module) {
213-
void (async () => {
214-
try {
215-
process.exit(await main());
216-
} catch (err) {
217-
console.error(err instanceof Error ? err.message : String(err));
218-
process.exit(1);
219-
}
220-
})();
224+
void run();
221225
}

pr-checks/config.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ export const OLDEST_SUPPORTED_MAJOR_VERSION = 3;
66
/** The `pr-checks` directory. */
77
export const PR_CHECKS_DIR = __dirname;
88

9+
/** The repository root. */
10+
export const REPO_ROOT = path.join(PR_CHECKS_DIR, "..");
11+
912
/** The path of the file configuring which checks shouldn't be required. */
1013
export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
1114

1215
/** The path to the esbuild metadata file. */
13-
export const BUNDLE_METADATA_FILE = path.join(PR_CHECKS_DIR, "..", "meta.json");
16+
export const BUNDLE_METADATA_FILE = path.join(REPO_ROOT, "meta.json");
1417

1518
/** The `src` directory. */
16-
const SOURCE_ROOT = path.join(PR_CHECKS_DIR, "..", "src");
19+
const SOURCE_ROOT = path.join(REPO_ROOT, "src");
1720

1821
/** The path to the built-in languages file. */
1922
export const BUILTIN_LANGUAGES_FILE = path.join(

0 commit comments

Comments
 (0)