Skip to content

Commit c889bd2

Browse files
authored
ci: Fix size limit comparison (#11282)
I inlined https://github.com/billyvg/github-fetch-workflow-artifact, basically, as it struggled to import this in esm, for whatever reason... now all the code is inlined, which is fine I guess 😬
1 parent 4e4f1da commit c889bd2

File tree

3 files changed

+188
-129
lines changed

3 files changed

+188
-129
lines changed

dev-packages/size-limit-gh-action/index.mjs

Lines changed: 181 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-lines */
12
import { promises as fs } from 'node:fs';
23
import path from 'node:path';
34
import { fileURLToPath } from 'node:url';
@@ -7,11 +8,10 @@ import * as core from '@actions/core';
78
import { exec } from '@actions/exec';
89
import { context, getOctokit } from '@actions/github';
910
import * as glob from '@actions/glob';
11+
import * as io from '@actions/io';
1012
import bytes from 'bytes';
1113
import { markdownTable } from 'markdown-table';
1214

13-
import download from 'github-fetch-workflow-artifact';
14-
1515
const SIZE_LIMIT_HEADING = '## size-limit report 📦 ';
1616
const ARTIFACT_NAME = 'size-limit-action';
1717
const RESULTS_FILE = 'size-limit-results.json';
@@ -229,20 +229,28 @@ async function run() {
229229
let current;
230230

231231
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, {
235233
...repo,
236234
artifactName: ARTIFACT_NAME,
237235
branch: comparisonBranch,
238-
downloadPath: __dirname,
239-
workflowEvent: 'push',
240236
workflowName: `${process.env.GITHUB_WORKFLOW || ''}`,
241237
});
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+
242250
base = JSON.parse(await fs.readFile(resultsFilePath, { encoding: 'utf8' }));
243251
} catch (error) {
244252
core.startGroup('Warning, unable to find base results');
245-
core.debug(error);
253+
core.error(error);
246254
core.endGroup();
247255
}
248256

@@ -295,4 +303,169 @@ async function run() {
295303
}
296304
}
297305

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+
298432
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+
}

dev-packages/size-limit-gh-action/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
"@actions/artifact": "1.1.2",
1818
"@actions/core": "1.10.1",
1919
"@actions/exec": "1.1.1",
20-
"@actions/github": "6.0.0",
20+
"@actions/io": "1.1.3",
21+
"@actions/github": "^5.0.0",
2122
"@actions/glob": "0.4.0",
2223
"bytes": "3.1.2",
23-
"github-fetch-workflow-artifact": "2.0.0",
2424
"markdown-table": "3.0.3"
2525
},
2626
"volta": {

0 commit comments

Comments
 (0)