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