Skip to content

Commit 0ce6883

Browse files
committed
Fix duplicate artifact downloads
1 parent df9ecea commit 0ce6883

File tree

4 files changed

+78
-40
lines changed

4 files changed

+78
-40
lines changed

dist/index.js

Lines changed: 26 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import type { ArtifactClient } from '@actions/artifact'
22
import * as core from '@actions/core'
33
import * as github from '@actions/github'
4-
import type { Comment, ProviderAPIClient } from '@code-pushup/ci'
4+
import type { Comment, GitBranch, ProviderAPIClient } from '@code-pushup/ci'
55
import type { components } from '@octokit/openapi-types'
6-
import { downloadReportArtifact } from './artifact'
6+
import path from 'node:path'
7+
import { downloadReportsArtifact, type DownloadedArtifact } from './artifact'
78
import type { GitHubRefs } from './refs'
89

910
export class GitHubApiClient implements ProviderAPIClient {
1011
readonly maxCommentChars = 65_536
1112

1213
private readonly octokit
1314

15+
private readonly artifactCache = new Map<string, DownloadedArtifact | null>()
16+
1417
constructor(
1518
private readonly token: string,
1619
private readonly refs: GitHubRefs,
@@ -54,13 +57,42 @@ export class GitHubApiClient implements ProviderAPIClient {
5457
core.debug(`Tried to download artifact without base branch, skipping`)
5558
return null
5659
}
57-
return downloadReportArtifact(
60+
const reports = await this.getReportsArtifact(this.refs.base)
61+
62+
if (reports == null) {
63+
return null
64+
}
65+
66+
const expectedFile = path.join(
67+
'.code-pushup',
68+
'.ci',
69+
project ?? '',
70+
'.current',
71+
'report.json'
72+
)
73+
74+
if (!reports.files.includes(expectedFile)) {
75+
core.warning(`Downloaded artifact doesn't contain ${expectedFile}`)
76+
return null
77+
}
78+
79+
return path.join(reports.downloadPath, expectedFile)
80+
}
81+
82+
private async getReportsArtifact(
83+
base: GitBranch
84+
): Promise<DownloadedArtifact | null> {
85+
if (this.artifactCache.has(base.sha)) {
86+
return this.artifactCache.get(base.sha) ?? null
87+
}
88+
const result = await downloadReportsArtifact(
5889
this.artifact,
5990
this.octokit,
60-
this.refs.base,
61-
this.token,
62-
project
91+
base,
92+
this.token
6393
)
94+
this.artifactCache.set(base.sha, result)
95+
return result
6496
}
6597

6698
private convertComment(

src/artifact.ts

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ import { readdir, rm } from 'node:fs/promises'
1111
import path from 'node:path'
1212
import type { ActionInputs } from './inputs'
1313

14+
export type DownloadedArtifact = {
15+
downloadPath: string
16+
files: string[]
17+
}
18+
1419
export const REPORT_ARTIFACT_NAME = 'code-pushup-report'
15-
const ARTIFACT_DIR = 'tmp'
20+
const ARTIFACTS_DIR = path.join('.github', 'artifacts')
1621

1722
export async function uploadArtifact(
1823
artifact: ArtifactClient,
@@ -30,13 +35,12 @@ export async function uploadArtifact(
3035
return id
3136
}
3237

33-
export async function downloadReportArtifact(
38+
export async function downloadReportsArtifact(
3439
artifact: ArtifactClient,
3540
octokit: ReturnType<typeof github.getOctokit>,
3641
branch: GitBranch,
37-
token: string,
38-
project: string | undefined
39-
): Promise<string | null> {
42+
token: string
43+
): Promise<DownloadedArtifact | null> {
4044
const {
4145
data: { workflow_id }
4246
} = await octokit.rest.actions.getWorkflowRun({
@@ -84,10 +88,11 @@ export async function downloadReportArtifact(
8488
`Found ${reportArtifact.name} artifact with ID ${reportArtifact.id} in workflow run ${workflowRun.id}`
8589
)
8690

87-
await rm(ARTIFACT_DIR, { recursive: true, force: true })
91+
const artifactDir = path.join(ARTIFACTS_DIR, branch.sha)
92+
await rm(artifactDir, { recursive: true, force: true })
8893
const { downloadPath } = await artifact.downloadArtifact(
8994
reportArtifact.id,
90-
{ findBy, path: ARTIFACT_DIR }
95+
{ findBy, path: artifactDir }
9196
)
9297
if (!downloadPath) {
9398
throw new Error('Unexpected empty downloadPath')
@@ -96,21 +101,7 @@ export async function downloadReportArtifact(
96101
core.debug(
97102
`Downloaded artifact to ${downloadPath}, contains files: ${files.join(', ')}`
98103
)
99-
100-
const expectedFile = path.join(
101-
'.code-pushup',
102-
'.ci',
103-
project ?? '',
104-
'.current',
105-
'report.json'
106-
)
107-
108-
if (!files.includes(expectedFile)) {
109-
core.warning(`Downloaded artifact doesn't contain ${expectedFile}`)
110-
return null
111-
}
112-
113-
return path.join(downloadPath, expectedFile)
104+
return { downloadPath, files }
114105
} catch (err) {
115106
if (err instanceof ArtifactNotFoundError) {
116107
core.info(

0 commit comments

Comments
 (0)