1+ /* eslint-disable max-lines */
12import { promises as fs } from 'node:fs' ;
23import path from 'node:path' ;
34import { fileURLToPath } from 'node:url' ;
@@ -7,11 +8,10 @@ import * as core from '@actions/core';
78import { exec } from '@actions/exec' ;
89import { context , getOctokit } from '@actions/github' ;
910import * as glob from '@actions/glob' ;
11+ import * as io from '@actions/io' ;
1012import bytes from 'bytes' ;
1113import { markdownTable } from 'markdown-table' ;
1214
13- import download from 'github-fetch-workflow-artifact' ;
14-
1515const SIZE_LIMIT_HEADING = '## size-limit report 📦 ' ;
1616const ARTIFACT_NAME = 'size-limit-action' ;
1717const RESULTS_FILE = 'size-limit-results.json' ;
@@ -229,29 +229,27 @@ async function run() {
229229 let current ;
230230
231231 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' ) ;
238240
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+ }
242244
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 , {
246246 ...repo ,
247247 artifactName : ARTIFACT_NAME ,
248- branch : comparisonBranch ,
248+ artifactId : artifacts . artifact . id ,
249249 downloadPath : __dirname ,
250- workflowEvent : 'push' ,
251- workflowName : `${ process . env . GITHUB_WORKFLOW || '' } ` ,
252250 } ) ;
253- core . warning ( 'Downloaded base results' ) ;
254- core . warning ( res ) ;
251+
252+ core . info ( 'Downloaded base results' ) ;
255253 base = JSON . parse ( await fs . readFile ( resultsFilePath , { encoding : 'utf8' } ) ) ;
256254 } catch ( error ) {
257255 core . startGroup ( 'Warning, unable to find base results' ) ;
@@ -308,4 +306,169 @@ async function run() {
308306 }
309307}
310308
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+
311435run ( ) ;
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