1
0
mirror of https://github.com/actions/upload-artifact.git synced 2026-02-26 13:42:35 +00:00

Upgrade the module to ESM and bump dependencies

This commit is contained in:
Daniel Kennedy
2026-02-25 12:57:27 -05:00
parent 47309c993a
commit f119f587c2
19 changed files with 2811 additions and 2234 deletions

View File

@ -1,8 +1,65 @@
import * as core from '@actions/core'
import artifact from '@actions/artifact'
import {run} from '../src/merge/merge-artifacts'
import {Inputs} from '../src/merge/constants'
import * as search from '../src/shared/search'
import {jest, describe, test, expect, beforeEach} from '@jest/globals'
// Mock @actions/github before importing modules that use it
jest.unstable_mockModule('@actions/github', () => ({
context: {
repo: {
owner: 'actions',
repo: 'toolkit'
},
runId: 123,
serverUrl: 'https://github.com'
},
getOctokit: jest.fn()
}))
// Mock @actions/core
jest.unstable_mockModule('@actions/core', () => ({
getInput: jest.fn(),
getBooleanInput: jest.fn(),
setOutput: jest.fn(),
setFailed: jest.fn(),
setSecret: jest.fn(),
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
startGroup: jest.fn(),
endGroup: jest.fn(),
isDebug: jest.fn(() => false),
getState: jest.fn(),
saveState: jest.fn(),
exportVariable: jest.fn(),
addPath: jest.fn(),
group: jest.fn((name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn((p: string) => p),
toWin32Path: jest.fn((p: string) => p),
toPosixPath: jest.fn((p: string) => p)
}))
// Mock fs/promises
const actualFsPromises = await import('fs/promises')
jest.unstable_mockModule('fs/promises', () => ({
...actualFsPromises,
mkdtemp:
jest.fn<() => Promise<string>>().mockResolvedValue('/tmp/merge-artifact'),
rm: jest.fn<() => Promise<void>>().mockResolvedValue(undefined)
}))
// Mock shared search module
const mockFindFilesToUpload = jest.fn<
() => Promise<{filesToUpload: string[]; rootDirectory: string}>
>()
jest.unstable_mockModule('../src/shared/search.js', () => ({
findFilesToUpload: mockFindFilesToUpload
}))
// Dynamic imports after mocking
const core = await import('@actions/core')
const artifact = await import('@actions/artifact')
const {run} = await import('../src/merge/merge-artifacts.js')
const {Inputs} = await import('../src/merge/constants.js')
const fixtures = {
artifactName: 'my-merged-artifact',
@ -34,27 +91,10 @@ const fixtures = {
]
}
jest.mock('@actions/github', () => ({
context: {
repo: {
owner: 'actions',
repo: 'toolkit'
},
runId: 123,
serverUrl: 'https://github.com'
}
}))
jest.mock('@actions/core')
jest.mock('fs/promises', () => ({
mkdtemp: jest.fn().mockResolvedValue('/tmp/merge-artifact'),
rm: jest.fn().mockResolvedValue(undefined)
}))
/* eslint-disable no-unused-vars */
const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
const inputs = {
const mockInputs = (
overrides?: Partial<{[K in (typeof Inputs)[keyof typeof Inputs]]?: any}>
) => {
const inputs: Record<string, any> = {
[Inputs.Name]: 'my-merged-artifact',
[Inputs.Pattern]: '*',
[Inputs.SeparateDirectories]: false,
@ -64,10 +104,14 @@ const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
...overrides
}
;(core.getInput as jest.Mock).mockImplementation((name: string) => {
return inputs[name]
})
;(core.getBooleanInput as jest.Mock).mockImplementation((name: string) => {
;(core.getInput as jest.Mock<typeof core.getInput>).mockImplementation(
(name: string) => {
return inputs[name]
}
)
;(
core.getBooleanInput as jest.Mock<typeof core.getBooleanInput>
).mockImplementation((name: string) => {
return inputs[name]
})
@ -77,44 +121,45 @@ const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
describe('merge', () => {
beforeEach(async () => {
mockInputs()
jest.clearAllMocks()
jest
.spyOn(artifact, 'listArtifacts')
.spyOn(artifact.default, 'listArtifacts')
.mockResolvedValue({artifacts: fixtures.artifacts})
jest.spyOn(artifact, 'downloadArtifact').mockResolvedValue({
jest.spyOn(artifact.default, 'downloadArtifact').mockResolvedValue({
downloadPath: fixtures.tmpDirectory
})
jest.spyOn(search, 'findFilesToUpload').mockResolvedValue({
mockFindFilesToUpload.mockResolvedValue({
filesToUpload: fixtures.filesToUpload,
rootDirectory: fixtures.tmpDirectory
})
jest.spyOn(artifact, 'uploadArtifact').mockResolvedValue({
jest.spyOn(artifact.default, 'uploadArtifact').mockResolvedValue({
size: 123,
id: 1337
})
jest
.spyOn(artifact, 'deleteArtifact')
.mockImplementation(async artifactName => {
const artifact = fixtures.artifacts.find(a => a.name === artifactName)
if (!artifact) throw new Error(`Artifact ${artifactName} not found`)
return {id: artifact.id}
.spyOn(artifact.default, 'deleteArtifact')
.mockImplementation(async (artifactName: string) => {
const found = fixtures.artifacts.find(a => a.name === artifactName)
if (!found) throw new Error(`Artifact ${artifactName} not found`)
return {id: found.id}
})
})
it('merges artifacts', async () => {
test('merges artifacts', async () => {
await run()
for (const a of fixtures.artifacts) {
expect(artifact.downloadArtifact).toHaveBeenCalledWith(a.id, {
expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(a.id, {
path: fixtures.tmpDirectory
})
}
expect(artifact.uploadArtifact).toHaveBeenCalledWith(
expect(artifact.default.uploadArtifact).toHaveBeenCalledWith(
fixtures.artifactName,
fixtures.filesToUpload,
fixtures.tmpDirectory,
@ -122,23 +167,23 @@ describe('merge', () => {
)
})
it('fails if no artifacts found', async () => {
test('fails if no artifacts found', async () => {
mockInputs({[Inputs.Pattern]: 'this-does-not-match'})
expect(run()).rejects.toThrow()
await expect(run()).rejects.toThrow()
expect(artifact.uploadArtifact).not.toBeCalled()
expect(artifact.downloadArtifact).not.toBeCalled()
expect(artifact.default.uploadArtifact).not.toHaveBeenCalled()
expect(artifact.default.downloadArtifact).not.toHaveBeenCalled()
})
it('supports custom compression level', async () => {
test('supports custom compression level', async () => {
mockInputs({
[Inputs.CompressionLevel]: 2
})
await run()
expect(artifact.uploadArtifact).toHaveBeenCalledWith(
expect(artifact.default.uploadArtifact).toHaveBeenCalledWith(
fixtures.artifactName,
fixtures.filesToUpload,
fixtures.tmpDirectory,
@ -146,14 +191,14 @@ describe('merge', () => {
)
})
it('supports custom retention days', async () => {
test('supports custom retention days', async () => {
mockInputs({
[Inputs.RetentionDays]: 7
})
await run()
expect(artifact.uploadArtifact).toHaveBeenCalledWith(
expect(artifact.default.uploadArtifact).toHaveBeenCalledWith(
fixtures.artifactName,
fixtures.filesToUpload,
fixtures.tmpDirectory,
@ -161,7 +206,7 @@ describe('merge', () => {
)
})
it('supports deleting artifacts after merge', async () => {
test('supports deleting artifacts after merge', async () => {
mockInputs({
[Inputs.DeleteMerged]: true
})
@ -169,7 +214,7 @@ describe('merge', () => {
await run()
for (const a of fixtures.artifacts) {
expect(artifact.deleteArtifact).toHaveBeenCalledWith(a.name)
expect(artifact.default.deleteArtifact).toHaveBeenCalledWith(a.name)
}
})
})