Skip to content

Commit 5a80681

Browse files
committed
Address review comments
1 parent bcffb2b commit 5a80681

2 files changed

Lines changed: 59 additions & 47 deletions

File tree

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

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import * as os from "node:os";
66
import * as path from "node:path";
77
import { afterEach, beforeEach, describe, it } from "node:test";
88

9-
import { getOctokit } from "@actions/github";
109
import * as sinon from "sinon";
1110

11+
import { type ApiClient, getApiClient } from "./api-client";
1212
import {
1313
COMMENT_MARKER,
1414
buildCommentBody,
@@ -198,31 +198,31 @@ describe("upsertSizeComment", async () => {
198198
const repo = "test-repo";
199199
const prNumber = 42;
200200

201-
let octokit: ReturnType<typeof getOctokit>;
201+
let client: ApiClient;
202202

203203
beforeEach(() => {
204-
octokit = getOctokit("test-token");
204+
client = getApiClient("test-token");
205205
});
206206

207207
afterEach(() => {
208208
sinon.restore();
209209
});
210210

211211
function stubExistingComments(comments: Array<{ id: number; body: string }>) {
212-
// upsertSizeComment calls `octokit.paginate(octokit.rest.issues.listComments, ...)`,
213-
// so stubbing `paginate` directly mocks the listing without depending on how
214-
// paginate walks Octokit's response (link headers etc.).
215-
return sinon.stub(octokit, "paginate").resolves(comments);
212+
// upsertSizeComment calls `client.paginate(...)`, so stubbing `paginate`
213+
// directly mocks the listing without depending on how paginate walks
214+
// Octokit's response (link headers etc.).
215+
return sinon.stub(client, "paginate").resolves(comments);
216216
}
217217

218218
await it("creates a new comment when none exists and the delta is significant", async () => {
219219
stubExistingComments([]);
220220
const createStub = sinon
221-
.stub(octokit.rest.issues, "createComment")
221+
.stub(client.rest.issues, "createComment")
222222
.resolves({ data: { id: 999 } } as never);
223223

224224
const result = await upsertSizeComment({
225-
octokit,
225+
client,
226226
owner,
227227
repo,
228228
prNumber,
@@ -246,11 +246,11 @@ describe("upsertSizeComment", async () => {
246246
// negative deltas.
247247
stubExistingComments([]);
248248
const createStub = sinon
249-
.stub(octokit.rest.issues, "createComment")
249+
.stub(client.rest.issues, "createComment")
250250
.resolves({ data: { id: 999 } } as never);
251251

252252
const result = await upsertSizeComment({
253-
octokit,
253+
client,
254254
owner,
255255
repo,
256256
prNumber,
@@ -265,11 +265,11 @@ describe("upsertSizeComment", async () => {
265265

266266
await it("skips when no existing comment and delta is below threshold", async () => {
267267
stubExistingComments([]);
268-
const createStub = sinon.stub(octokit.rest.issues, "createComment");
269-
const updateStub = sinon.stub(octokit.rest.issues, "updateComment");
268+
const createStub = sinon.stub(client.rest.issues, "createComment");
269+
const updateStub = sinon.stub(client.rest.issues, "updateComment");
270270

271271
const result = await upsertSizeComment({
272-
octokit,
272+
client,
273273
owner,
274274
repo,
275275
prNumber,
@@ -286,11 +286,11 @@ describe("upsertSizeComment", async () => {
286286
await it("updates the existing comment when the delta is significant", async () => {
287287
stubExistingComments([{ id: 7, body: `${COMMENT_MARKER}\nold body` }]);
288288
const updateStub = sinon
289-
.stub(octokit.rest.issues, "updateComment")
289+
.stub(client.rest.issues, "updateComment")
290290
.resolves({ data: { id: 7 } } as never);
291291

292292
const result = await upsertSizeComment({
293-
octokit,
293+
client,
294294
owner,
295295
repo,
296296
prNumber,
@@ -311,11 +311,11 @@ describe("upsertSizeComment", async () => {
311311
// gets reduced below the threshold by a follow-up commit.
312312
stubExistingComments([{ id: 7, body: `${COMMENT_MARKER}\nold body` }]);
313313
const updateStub = sinon
314-
.stub(octokit.rest.issues, "updateComment")
314+
.stub(client.rest.issues, "updateComment")
315315
.resolves({ data: { id: 7 } } as never);
316316

317317
const result = await upsertSizeComment({
318-
octokit,
318+
client,
319319
owner,
320320
repo,
321321
prNumber,

pr-checks/check-repo-size.ts

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { spawn } from "node:child_process";
1414
import * as path from "node:path";
1515
import { parseArgs } from "node:util";
1616

17-
import { getOctokit } from "@actions/github";
17+
import { type ApiClient, getApiClient } from "./api-client";
1818

1919
/** Hidden marker used to find the existing sticky comment on a PR. */
2020
export const COMMENT_MARKER = "<!-- repo-size-diff-bot -->";
@@ -30,13 +30,11 @@ export const DEFAULT_REPOSITORY = "github/codeql-action";
3030
*/
3131
export const SIGNIFICANT_DELTA_FRACTION = 0.1;
3232

33-
export type Octokit = ReturnType<typeof getOctokit>;
34-
3533
/**
3634
* Stream `git archive --format=tar.gz <ref>` and count the compressed bytes.
3735
*
38-
* `git archive` only includes tracked files, so we will ignore directories like `node_modules` and
39-
* `build` that aren't downloaded when starting up a CodeQL job.
36+
* `git archive` only includes tracked files, so untracked directories like `node_modules` and
37+
* `build` aren't counted in the size downloaded when starting up a CodeQL job.
4038
*/
4139
export async function measureArchiveSize(
4240
ref: string,
@@ -114,8 +112,8 @@ export function buildCommentBody(opts: CommentBodyOptions): string {
114112
`| **Delta** | **${formatBytes(delta, true)} (${signedDelta} bytes, ${formatPercent(delta / baseSize)})** |`,
115113
"",
116114
"Sizes are measured by streaming `git archive --format=tar.gz <ref>`, " +
117-
"which includes all tracked files and excludes `node_modules` and " +
118-
"other untracked or git-ignored files. The compressed checkout is " +
115+
"which includes tracked files and excludes untracked files such as " +
116+
"`node_modules`. The compressed checkout is " +
119117
"downloaded by every consumer of this Action, so changes here directly " +
120118
`affect Action download time.${runUrlLine}`,
121119
].join("\n");
@@ -134,7 +132,7 @@ export function isDeltaSignificant(
134132
}
135133

136134
export interface UpsertOptions {
137-
octokit: Octokit;
135+
client: ApiClient;
138136
owner: string;
139137
repo: string;
140138
prNumber: number;
@@ -156,20 +154,23 @@ export type UpsertResult =
156154
export async function upsertSizeComment(
157155
opts: UpsertOptions,
158156
): Promise<UpsertResult> {
159-
const { octokit, owner, repo, prNumber, body, delta, baseSize } = opts;
157+
const { client, owner, repo, prNumber, body, delta, baseSize } = opts;
160158

161-
const comments = await octokit.paginate(octokit.rest.issues.listComments, {
162-
owner,
163-
repo,
164-
issue_number: prNumber,
165-
per_page: 100,
166-
});
159+
const comments = await client.paginate(
160+
"GET /repos/{owner}/{repo}/issues/{issue_number}/comments",
161+
{
162+
owner,
163+
repo,
164+
issue_number: prNumber,
165+
per_page: 100,
166+
},
167+
);
167168
const existing = comments.find((c) =>
168169
(c.body ?? "").includes(COMMENT_MARKER),
169170
);
170171

171172
if (existing) {
172-
await octokit.rest.issues.updateComment({
173+
await client.rest.issues.updateComment({
173174
owner,
174175
repo,
175176
comment_id: existing.id,
@@ -179,7 +180,7 @@ export async function upsertSizeComment(
179180
}
180181

181182
if (isDeltaSignificant(delta, baseSize, SIGNIFICANT_DELTA_FRACTION)) {
182-
const { data } = await octokit.rest.issues.createComment({
183+
const { data } = await client.rest.issues.createComment({
183184
owner,
184185
repo,
185186
issue_number: prNumber,
@@ -198,10 +199,12 @@ export async function upsertSizeComment(
198199
}
199200

200201
interface MainArgs {
201-
/** Base ref of the PR. Defaults to `main`, and is prefixed with `origin/` when passed to git. */
202+
/** Base ref of the PR. Defaults to `main`, and is used as the label in the PR comment. */
202203
baseRef: string;
203-
/** Numeric PR number used to find / create / update the sticky comment. */
204-
prNumber: number;
204+
/** Base commit to archive. Defaults to `origin/main` for local dry runs. */
205+
baseCommitish: string;
206+
/** Numeric PR number used to find / create / update the sticky comment. Required outside dry-run. */
207+
prNumber?: number;
205208
/** `owner/repo` slug, defaulting to `github/codeql-action`, split before being passed to Octokit. */
206209
ownerRepo: string;
207210
/** Optional URL of the workflow run, surfaced in the comment footer. */
@@ -220,23 +223,29 @@ export function readArgs(): MainArgs {
220223
strict: true,
221224
});
222225

226+
const dryRun = values["dry-run"] ?? false;
223227
const baseRef = process.env.BASE_REF ?? DEFAULT_BASE_REF;
228+
const baseCommitish = process.env.BASE_SHA ?? `origin/${baseRef}`;
224229
const prNumberStr = process.env.PR_NUMBER;
225230
const repo = process.env.GITHUB_REPOSITORY ?? DEFAULT_REPOSITORY;
226231

227-
if (!prNumberStr) throw new Error("Missing PR_NUMBER env var");
228-
229-
const prNumber = Number.parseInt(prNumberStr, 10);
230-
if (!Number.isFinite(prNumber)) {
231-
throw new Error(`Invalid PR_NUMBER value: ${prNumberStr}`);
232+
let prNumber: number | undefined;
233+
if (prNumberStr) {
234+
prNumber = Number.parseInt(prNumberStr, 10);
235+
if (!Number.isFinite(prNumber)) {
236+
throw new Error(`Invalid PR_NUMBER value: ${prNumberStr}`);
237+
}
238+
} else if (!dryRun) {
239+
throw new Error("Missing PR_NUMBER env var");
232240
}
233241

234242
return {
235243
baseRef,
244+
baseCommitish,
236245
prNumber,
237246
ownerRepo: repo,
238247
runUrl: process.env.RUN_URL,
239-
dryRun: values["dry-run"] ?? false,
248+
dryRun,
240249
token: process.env.GITHUB_TOKEN,
241250
};
242251
}
@@ -248,8 +257,8 @@ async function main(): Promise<number> {
248257
// root is always the parent directory.
249258
const repoRoot = path.resolve(__dirname, "..");
250259

251-
console.log(`Measuring base archive size for origin/${args.baseRef}...`);
252-
const baseSize = await measureArchiveSize(`origin/${args.baseRef}`, repoRoot);
260+
console.log(`Measuring base archive size for ${args.baseCommitish}...`);
261+
const baseSize = await measureArchiveSize(args.baseCommitish, repoRoot);
253262
console.log(` ${baseSize} bytes`);
254263

255264
console.log("Measuring PR archive size for HEAD...");
@@ -285,14 +294,17 @@ async function main(): Promise<number> {
285294
"GITHUB_TOKEN env var is required when not running with --dry-run",
286295
);
287296
}
297+
if (args.prNumber === undefined) {
298+
throw new Error("Missing PR_NUMBER env var");
299+
}
288300

289301
const [owner, repo] = args.ownerRepo.split("/");
290302
if (!owner || !repo) {
291303
throw new Error(`Invalid GITHUB_REPOSITORY value: ${args.ownerRepo}`);
292304
}
293305

294306
const result = await upsertSizeComment({
295-
octokit: getOctokit(args.token),
307+
client: getApiClient(args.token),
296308
owner,
297309
repo,
298310
prNumber: args.prNumber,

0 commit comments

Comments
 (0)