@@ -14,7 +14,7 @@ import { spawn } from "node:child_process";
1414import * as path from "node:path" ;
1515import { 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. */
2020export const COMMENT_MARKER = "<!-- repo-size-diff-bot -->" ;
@@ -30,13 +30,11 @@ export const DEFAULT_REPOSITORY = "github/codeql-action";
3030 */
3131export 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 */
4139export 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
136134export interface UpsertOptions {
137- octokit : Octokit ;
135+ client : ApiClient ;
138136 owner : string ;
139137 repo : string ;
140138 prNumber : number ;
@@ -156,20 +154,23 @@ export type UpsertResult =
156154export 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
200201interface 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