1
+ /* eslint-disable max-lines */
1
2
import { promises as fs } from 'node:fs' ;
2
3
import path from 'node:path' ;
3
4
import { fileURLToPath } from 'node:url' ;
@@ -7,11 +8,10 @@ import * as core from '@actions/core';
7
8
import { exec } from '@actions/exec' ;
8
9
import { context , getOctokit } from '@actions/github' ;
9
10
import * as glob from '@actions/glob' ;
11
+ import * as io from '@actions/io' ;
10
12
import bytes from 'bytes' ;
11
13
import { markdownTable } from 'markdown-table' ;
12
14
13
- import download from 'github-fetch-workflow-artifact' ;
14
-
15
15
const SIZE_LIMIT_HEADING = '## size-limit report 📦 ' ;
16
16
const ARTIFACT_NAME = 'size-limit-action' ;
17
17
const RESULTS_FILE = 'size-limit-results.json' ;
@@ -229,20 +229,28 @@ async function run() {
229
229
let current ;
230
230
231
231
try {
232
- // Ignore failures here as it is likely that this only happens when introducing size-limit
233
- // and this has not been run on the main branch yet
234
- await download ( octokit , {
232
+ const artifacts = await getArtifactsForBranchAndWorkflow ( octokit , {
235
233
...repo ,
236
234
artifactName : ARTIFACT_NAME ,
237
235
branch : comparisonBranch ,
238
- downloadPath : __dirname ,
239
- workflowEvent : 'push' ,
240
236
workflowName : `${ process . env . GITHUB_WORKFLOW || '' } ` ,
241
237
} ) ;
238
+
239
+ if ( ! artifacts ) {
240
+ throw new Error ( 'No artifacts found' ) ;
241
+ }
242
+
243
+ await downloadOtherWorkflowArtifact ( octokit , {
244
+ ...repo ,
245
+ artifactName : ARTIFACT_NAME ,
246
+ artifactId : artifacts . artifact . id ,
247
+ downloadPath : __dirname ,
248
+ } ) ;
249
+
242
250
base = JSON . parse ( await fs . readFile ( resultsFilePath , { encoding : 'utf8' } ) ) ;
243
251
} catch ( error ) {
244
252
core . startGroup ( 'Warning, unable to find base results' ) ;
245
- core . debug ( error ) ;
253
+ core . error ( error ) ;
246
254
core . endGroup ( ) ;
247
255
}
248
256
@@ -295,4 +303,169 @@ async function run() {
295
303
}
296
304
}
297
305
306
+ // max pages of workflows to pagination through
307
+ const DEFAULT_MAX_PAGES = 50 ;
308
+ // max results per page
309
+ const DEFAULT_PAGE_LIMIT = 10 ;
310
+
311
+ /**
312
+ * Fetch artifacts from a workflow run from a branch
313
+ *
314
+ * This is a bit hacky since GitHub Actions currently does not directly
315
+ * support downloading artifacts from other workflows
316
+ */
317
+ /**
318
+ * Fetch artifacts from a workflow run from a branch
319
+ *
320
+ * This is a bit hacky since GitHub Actions currently does not directly
321
+ * support downloading artifacts from other workflows
322
+ */
323
+ export async function getArtifactsForBranchAndWorkflow ( octokit , { owner, repo, workflowName, branch, artifactName } ) {
324
+ core . startGroup ( `getArtifactsForBranchAndWorkflow - workflow:"${ workflowName } ", branch:"${ branch } "` ) ;
325
+
326
+ let repositoryWorkflow = null ;
327
+
328
+ // For debugging
329
+ const allWorkflows = [ ] ;
330
+
331
+ //
332
+ // Find workflow id from `workflowName`
333
+ //
334
+ for await ( const response of octokit . paginate . iterator ( octokit . rest . actions . listRepoWorkflows , {
335
+ owner,
336
+ repo,
337
+ } ) ) {
338
+ const targetWorkflow = response . data . find ( ( { name } ) => name === workflowName ) ;
339
+
340
+ allWorkflows . push ( ...response . data . map ( ( { name } ) => name ) ) ;
341
+
342
+ // If not found in responses, continue to search on next page
343
+ if ( ! targetWorkflow ) {
344
+ continue ;
345
+ }
346
+
347
+ repositoryWorkflow = targetWorkflow ;
348
+ break ;
349
+ }
350
+
351
+ if ( ! repositoryWorkflow ) {
352
+ core . info (
353
+ `Unable to find workflow with name "${ workflowName } " in the repository. Found workflows: ${ allWorkflows . join (
354
+ ', ' ,
355
+ ) } `,
356
+ ) ;
357
+ core . endGroup ( ) ;
358
+ return null ;
359
+ }
360
+
361
+ const workflow_id = repositoryWorkflow . id ;
362
+
363
+ let currentPage = 0 ;
364
+ const completedWorkflowRuns = [ ] ;
365
+
366
+ for await ( const response of octokit . paginate . iterator ( octokit . rest . actions . listWorkflowRuns , {
367
+ owner,
368
+ repo,
369
+ workflow_id,
370
+ branch,
371
+ status : 'completed' ,
372
+ per_page : DEFAULT_PAGE_LIMIT ,
373
+ event : 'push' ,
374
+ } ) ) {
375
+ if ( ! response . data . length ) {
376
+ core . warning ( `Workflow ${ workflow_id } not found in branch ${ branch } ` ) ;
377
+ core . endGroup ( ) ;
378
+ return null ;
379
+ }
380
+
381
+ // Do not allow downloading artifacts from a fork.
382
+ completedWorkflowRuns . push (
383
+ ...response . data . filter ( workflowRun => workflowRun . head_repository . full_name === `${ owner } /${ repo } ` ) ,
384
+ ) ;
385
+
386
+ if ( completedWorkflowRuns . length ) {
387
+ break ;
388
+ }
389
+
390
+ if ( currentPage > DEFAULT_MAX_PAGES ) {
391
+ core . warning ( `Workflow ${ workflow_id } not found in branch: ${ branch } ` ) ;
392
+ core . endGroup ( ) ;
393
+ return null ;
394
+ }
395
+
396
+ currentPage ++ ;
397
+ }
398
+
399
+ // Search through workflow artifacts until we find a workflow run w/ artifact name that we are looking for
400
+ for ( const workflowRun of completedWorkflowRuns ) {
401
+ core . info ( `Checking artifacts for workflow run: ${ workflowRun . html_url } ` ) ;
402
+
403
+ const {
404
+ data : { artifacts } ,
405
+ } = await octokit . rest . actions . listWorkflowRunArtifacts ( {
406
+ owner,
407
+ repo,
408
+ run_id : workflowRun . id ,
409
+ } ) ;
410
+
411
+ if ( ! artifacts ) {
412
+ core . warning (
413
+ `Unable to fetch artifacts for branch: ${ branch } , workflow: ${ workflow_id } , workflowRunId: ${ workflowRun . id } ` ,
414
+ ) ;
415
+ } else {
416
+ const foundArtifact = artifacts . find ( ( { name } ) => name === artifactName ) ;
417
+ if ( foundArtifact ) {
418
+ core . info ( `Found suitable artifact: ${ foundArtifact . url } ` ) ;
419
+ return {
420
+ artifact : foundArtifact ,
421
+ workflowRun,
422
+ } ;
423
+ }
424
+ }
425
+ }
426
+
427
+ core . warning ( `Artifact not found: ${ artifactName } ` ) ;
428
+ core . endGroup ( ) ;
429
+ return null ;
430
+ }
431
+
298
432
run ( ) ;
433
+
434
+ /**
435
+ * Use GitHub API to fetch artifact download url, then
436
+ * download and extract artifact to `downloadPath`
437
+ */
438
+ async function downloadOtherWorkflowArtifact ( octokit , { owner, repo, artifactId, artifactName, downloadPath } ) {
439
+ const artifact = await octokit . rest . actions . downloadArtifact ( {
440
+ owner,
441
+ repo,
442
+ artifact_id : artifactId ,
443
+ archive_format : 'zip' ,
444
+ } ) ;
445
+
446
+ // Make sure output path exists
447
+ try {
448
+ await io . mkdirP ( downloadPath ) ;
449
+ } catch {
450
+ // ignore errors
451
+ }
452
+
453
+ const downloadFile = path . resolve ( downloadPath , `${ artifactName } .zip` ) ;
454
+
455
+ await exec ( 'wget' , [
456
+ '-nv' ,
457
+ '--retry-connrefused' ,
458
+ '--waitretry=1' ,
459
+ '--read-timeout=20' ,
460
+ '--timeout=15' ,
461
+ '-t' ,
462
+ '0' ,
463
+ '-O' ,
464
+ downloadFile ,
465
+ artifact . url ,
466
+ ] ) ;
467
+
468
+ await exec ( 'unzip' , [ '-q' , '-d' , downloadPath , downloadFile ] , {
469
+ silent : true ,
470
+ } ) ;
471
+ }
0 commit comments