Bump to core-3.0.0, move to vitest, support ESM modules (#587)

This commit is contained in:
Nick Cipollo
2026-02-01 17:51:43 -05:00
committed by GitHub
parent 5b3313d377
commit 3f973430f2
36 changed files with 36195 additions and 11507 deletions

5
.gitignore vendored
View File

@@ -92,7 +92,7 @@ fabric.properties
# Markdown Navigator plugin # Markdown Navigator plugin
.idea/**/markdown-navigator.xml .idea/**/markdown-navigator.xml
.idea/**/markdown-navigator/ .idea/**/markdown-navigator/
.idea/copilot.*
# End of https://www.gitignore.io/api/webstorm # End of https://www.gitignore.io/api/webstorm
# Coverage # Coverage
@@ -100,3 +100,6 @@ coverage
# Ignore lib, it contains intermediates # Ignore lib, it contains intermediates
/lib /lib
# Claude
.claude/settings.local.json

View File

@@ -0,0 +1,9 @@
import { vi } from "vitest"
export const debug = vi.fn()
export const getBooleanInput = vi.fn()
export const getInput = vi.fn()
export const notice = vi.fn()
export const setFailed = vi.fn()
export const setOutput = vi.fn()
export const warning = vi.fn()

8
__mocks__/fs.ts Normal file
View File

@@ -0,0 +1,8 @@
import { vi } from "vitest"
export const createReadStream = vi.fn()
export const statSync = vi.fn()
export const readFileSync = vi.fn()
export const writeFileSync = vi.fn()
export const existsSync = vi.fn()
export const realpathSync = vi.fn()

View File

@@ -1,11 +1,12 @@
import { Action } from "../src/Action" import { beforeEach, describe, expect, it, vi } from "vitest"
import type { ActionSkipper } from "../src/ActionSkipper" import { Action } from "../src/Action.js"
import { Artifact } from "../src/Artifact" import type { ActionSkipper } from "../src/ActionSkipper.js"
import type { ArtifactDestroyer } from "../src/ArtifactDestroyer" import { Artifact } from "../src/Artifact.js"
import type { ArtifactUploader } from "../src/ArtifactUploader" import type { ArtifactDestroyer } from "../src/ArtifactDestroyer.js"
import type { Inputs } from "../src/Inputs" import type { ArtifactUploader } from "../src/ArtifactUploader.js"
import type { Outputs } from "../src/Outputs" import type { Inputs } from "../src/Inputs.js"
import type { Releases } from "../src/Releases" import type { Outputs } from "../src/Outputs.js"
import type { Releases } from "../src/Releases.js"
const TEST_URLS = { const TEST_URLS = {
UPLOAD_URL: "http://api.example.com", UPLOAD_URL: "http://api.example.com",
@@ -14,18 +15,18 @@ const TEST_URLS = {
ZIPBALL_URL: "https://api.github.com/repos/owner/repo/zipball/v1.0.0", ZIPBALL_URL: "https://api.github.com/repos/owner/repo/zipball/v1.0.0",
} as const } as const
const applyReleaseDataMock = jest.fn() const applyReleaseDataMock = vi.fn()
const applyAssetUrlsMock = jest.fn() const applyAssetUrlsMock = vi.fn()
const artifactDestroyMock = jest.fn() const artifactDestroyMock = vi.fn()
const createMock = jest.fn() const createMock = vi.fn()
const deleteMock = jest.fn() const deleteMock = vi.fn()
const getMock = jest.fn() const getMock = vi.fn()
const listArtifactsMock = jest.fn() const listArtifactsMock = vi.fn()
const listMock = jest.fn() const listMock = vi.fn()
const shouldSkipMock = jest.fn() const shouldSkipMock = vi.fn()
const updateMock = jest.fn() const updateMock = vi.fn()
const uploadMock = jest.fn() const uploadMock = vi.fn()
const genReleaseNotesMock = jest.fn() const genReleaseNotesMock = vi.fn()
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")] const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
@@ -34,7 +35,7 @@ const createDraft = true
const createName = "createName" const createName = "createName"
const commit = "commit" const commit = "commit"
const discussionCategory = "discussionCategory" const discussionCategory = "discussionCategory"
const generateReleaseNotes = true const _generateReleaseNotes = true
const id = 100 const id = 100
const createPrerelease = true const createPrerelease = true
const releaseId = 101 const releaseId = 101
@@ -55,6 +56,7 @@ describe("Action", () => {
beforeEach(() => { beforeEach(() => {
applyReleaseDataMock.mockClear() applyReleaseDataMock.mockClear()
applyAssetUrlsMock.mockClear() applyAssetUrlsMock.mockClear()
artifactDestroyMock.mockClear()
createMock.mockClear() createMock.mockClear()
genReleaseNotesMock.mockClear() genReleaseNotesMock.mockClear()
getMock.mockClear() getMock.mockClear()
@@ -149,7 +151,18 @@ describe("Action", () => {
}) })
it("creates release with combined body and generated release notes using previous tag", async () => { it("creates release with combined body and generated release notes using previous tag", async () => {
const action = createAction(false, false, false, true, false, createBody, true, createDraft, updateBody, previousTag) const action = createAction(
false,
false,
false,
true,
false,
createBody,
true,
createDraft,
updateBody,
previousTag
)
await action.perform() await action.perform()
@@ -209,8 +222,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -238,8 +251,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -262,8 +275,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -275,8 +288,8 @@ describe("Action", () => {
expect(artifactDestroyMock).toHaveBeenCalledWith(releaseId) expect(artifactDestroyMock).toHaveBeenCalledWith(releaseId)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -288,8 +301,8 @@ describe("Action", () => {
expect(artifactDestroyMock).not.toHaveBeenCalled() expect(artifactDestroyMock).not.toHaveBeenCalled()
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -456,8 +469,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -488,8 +501,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -513,8 +526,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -578,8 +591,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -610,8 +623,8 @@ describe("Action", () => {
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -695,8 +708,8 @@ describe("Action", () => {
// Should apply the immutable release data instead of the original // Should apply the immutable release data instead of the original
expect(applyReleaseDataMock).toHaveBeenCalledWith(immutableReleaseResponse.data) expect(applyReleaseDataMock).toHaveBeenCalledWith(immutableReleaseResponse.data)
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -705,7 +718,7 @@ describe("Action", () => {
const error = { status: 404 } const error = { status: 404 }
getMock.mockRejectedValue(error) getMock.mockRejectedValue(error)
listMock.mockResolvedValue({ data: [] }) // No draft releases found listMock.mockResolvedValue({ data: [] }) // No draft releases found
const immutableReleaseResponse = { const immutableReleaseResponse = {
data: { data: {
id: 888, id: 888,
@@ -749,8 +762,8 @@ describe("Action", () => {
// Should apply the immutable release data instead of the original // Should apply the immutable release data instead of the original
expect(applyReleaseDataMock).toHaveBeenCalledWith(immutableReleaseResponse.data) expect(applyReleaseDataMock).toHaveBeenCalledWith(immutableReleaseResponse.data)
assertAssetUrlsApplied({ assertAssetUrlsApplied({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
}) })
@@ -788,7 +801,7 @@ describe("Action", () => {
inputArtifact = [] inputArtifact = []
} }
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = vi.fn<() => Releases>(() => {
return { return {
create: createMock, create: createMock,
deleteArtifact: deleteMock, deleteArtifact: deleteMock,
@@ -796,7 +809,7 @@ describe("Action", () => {
listArtifactsForRelease: listArtifactsMock, listArtifactsForRelease: listArtifactsMock,
listReleases: listMock, listReleases: listMock,
update: updateMock, update: updateMock,
uploadArtifact: jest.fn(), uploadArtifact: vi.fn(),
generateReleaseNotes: genReleaseNotesMock, generateReleaseNotes: genReleaseNotesMock,
} }
}) })
@@ -835,11 +848,11 @@ describe("Action", () => {
}, },
}) })
uploadMock.mockResolvedValue({ uploadMock.mockResolvedValue({
"art1": "https://github.com/owner/repo/releases/download/v1.0.0/art1", art1: "https://github.com/owner/repo/releases/download/v1.0.0/art1",
"art2": "https://github.com/owner/repo/releases/download/v1.0.0/art2", art2: "https://github.com/owner/repo/releases/download/v1.0.0/art2",
}) })
const MockInputs = jest.fn<Inputs, any>(() => { const MockInputs = vi.fn<() => Inputs>(() => {
return { return {
allowUpdates, allowUpdates,
artifactErrorsFailBuild: true, artifactErrorsFailBuild: true,
@@ -869,35 +882,35 @@ describe("Action", () => {
omitBodyDuringUpdate, omitBodyDuringUpdate,
} }
}) })
const MockOutputs = jest.fn<Outputs, any>(() => { const MockOutputs = vi.fn<() => Outputs>(() => {
return { return {
applyReleaseData: applyReleaseDataMock, applyReleaseData: applyReleaseDataMock,
applyAssetUrls: applyAssetUrlsMock, applyAssetUrls: applyAssetUrlsMock,
} }
}) })
const MockUploader = jest.fn<ArtifactUploader, any>(() => { const MockUploader = vi.fn<() => ArtifactUploader>(() => {
return { return {
uploadArtifacts: uploadMock, uploadArtifacts: uploadMock,
} }
}) })
const MockArtifactDestroyer = jest.fn<ArtifactDestroyer, any>(() => { const MockArtifactDestroyer = vi.fn<() => ArtifactDestroyer>(() => {
return { return {
destroyArtifacts: artifactDestroyMock, destroyArtifacts: artifactDestroyMock,
} }
}) })
const MockActionSkipper = jest.fn<ActionSkipper, any>(() => { const MockActionSkipper = vi.fn<() => ActionSkipper>(() => {
return { return {
shouldSkip: shouldSkipMock, shouldSkip: shouldSkipMock,
} }
}) })
const inputs = new MockInputs() const inputs = MockInputs()
const outputs = new MockOutputs() const outputs = MockOutputs()
const releases = new MockReleases() const releases = MockReleases()
const uploader = new MockUploader() const uploader = MockUploader()
const artifactDestroyer = new MockArtifactDestroyer() const artifactDestroyer = MockArtifactDestroyer()
const actionSkipper = new MockActionSkipper() const actionSkipper = MockActionSkipper()
return new Action(inputs, outputs, releases, uploader, artifactDestroyer, actionSkipper) return new Action(inputs, outputs, releases, uploader, artifactDestroyer, actionSkipper)
} }

View File

@@ -1,19 +1,20 @@
import { ReleaseActionSkipper } from "../src/ActionSkipper" import { describe, expect, it, vi } from "vitest"
import type { Releases } from "../src/Releases" import { ReleaseActionSkipper } from "../src/ActionSkipper.js"
import type { Releases } from "../src/Releases.js"
describe("shouldSkip", () => { describe("shouldSkip", () => {
const getMock = jest.fn() const getMock = vi.fn()
const tag = "tag" const tag = "tag"
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = vi.fn<() => Releases>(() => {
return { return {
create: jest.fn(), create: vi.fn(),
deleteArtifact: jest.fn(), deleteArtifact: vi.fn(),
getByTag: getMock, getByTag: getMock,
listArtifactsForRelease: jest.fn(), listArtifactsForRelease: vi.fn(),
listReleases: jest.fn(), listReleases: vi.fn(),
update: jest.fn(), update: vi.fn(),
uploadArtifact: jest.fn(), uploadArtifact: vi.fn(),
generateReleaseNotes: jest.fn(), generateReleaseNotes: vi.fn(),
} }
}) })

View File

@@ -1,16 +1,19 @@
import { Artifact } from "../src/Artifact" import * as fs from "node:fs"
import { describe, expect, it, vi } from "vitest"
import { Artifact } from "../src/Artifact.js"
vi.mock("fs")
const contentLength = 42 const contentLength = 42
const fakeReadStream = {} const fakeReadStream = {}
jest.mock("fs", () => { const mockCreateReadStream = vi.mocked(fs.createReadStream)
return { const mockStatSync = vi.mocked(fs.statSync)
createReadStream: () => fakeReadStream,
statSync: () => { // biome-ignore lint/suspicious/noExplicitAny: Mock object for testing
return { size: contentLength } mockCreateReadStream.mockReturnValue(fakeReadStream as any)
}, // biome-ignore lint/suspicious/noExplicitAny: Partial Stats object for testing
} mockStatSync.mockReturnValue({ size: contentLength } as any)
})
describe("Artifact", () => { describe("Artifact", () => {
it("defaults contentType to raw", () => { it("defaults contentType to raw", () => {

View File

@@ -1,10 +1,11 @@
import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer" import { beforeEach, describe, expect, it, vi } from "vitest"
import type { Releases } from "../src/Releases" import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer.js"
import type { Releases } from "../src/Releases.js"
const releaseId = 100 const releaseId = 100
const deleteMock = jest.fn() const deleteMock = vi.fn()
const listArtifactsMock = jest.fn() const listArtifactsMock = vi.fn()
describe("ArtifactDestroyer", () => { describe("ArtifactDestroyer", () => {
beforeEach(() => { beforeEach(() => {
@@ -45,26 +46,26 @@ describe("ArtifactDestroyer", () => {
}) })
function createDestroyer(): GithubArtifactDestroyer { function createDestroyer(): GithubArtifactDestroyer {
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = vi.fn<() => Releases>(() => {
return { return {
create: jest.fn(), create: vi.fn(),
deleteArtifact: deleteMock, deleteArtifact: deleteMock,
getByTag: jest.fn(), getByTag: vi.fn(),
listArtifactsForRelease: listArtifactsMock, listArtifactsForRelease: listArtifactsMock,
listReleases: jest.fn(), listReleases: vi.fn(),
update: jest.fn(), update: vi.fn(),
uploadArtifact: jest.fn(), uploadArtifact: vi.fn(),
generateReleaseNotes: jest.fn(), generateReleaseNotes: vi.fn(),
} }
}) })
return new GithubArtifactDestroyer(new MockReleases()) return new GithubArtifactDestroyer(MockReleases())
} }
function mockDeleteError(): any { function mockDeleteError(): void {
deleteMock.mockRejectedValue("error") deleteMock.mockRejectedValue("error")
} }
function mockDeleteSuccess(): any { function mockDeleteSuccess(): void {
deleteMock.mockResolvedValue({}) deleteMock.mockResolvedValue({})
} }

View File

@@ -1,32 +1,33 @@
const warnMock = jest.fn() import * as fs from "node:fs"
import * as core from "@actions/core"
import { beforeEach, describe, expect, it, vi } from "vitest"
import { FileArtifactGlobber } from "../src/ArtifactGlobber" vi.mock("@actions/core")
import { Globber } from "../src/Globber" vi.mock("fs")
import { Artifact } from "../src/Artifact"
import { expandTilde } from "../src/PathExpander" import { Artifact } from "../src/Artifact.js"
import { FileArtifactGlobber } from "../src/ArtifactGlobber.js"
import type { Globber } from "../src/Globber.js"
import { expandTilde } from "../src/PathExpander.js"
const warnMock = vi.mocked(core.warning)
const mockStatSync = vi.mocked(fs.statSync)
// biome-ignore lint/suspicious/noExplicitAny: fs.realpathSync has overloads that are difficult to type
const mockRealpathSync = vi.mocked(fs.realpathSync as any)
const contentType = "raw" const contentType = "raw"
const globMock = jest.fn() const globMock = vi.fn()
const globResults = ["file1", "file2"] const globResults = ["file1", "file2"]
jest.mock("@actions/core", () => { mockStatSync.mockReturnValue({
return { warning: warnMock } isDirectory(): boolean {
}) return false
},
// biome-ignore lint/suspicious/noExplicitAny: Partial Stats object for testing
} as any)
jest.mock("fs", () => { // biome-ignore lint/suspicious/noExplicitAny: Mock return value for testing
return { mockRealpathSync.mockReturnValue(false as any)
statSync: () => {
return {
isDirectory(): boolean {
return false
},
}
},
realpathSync: () => {
return false
},
}
})
describe("ArtifactGlobber", () => { describe("ArtifactGlobber", () => {
beforeEach(() => { beforeEach(() => {
@@ -90,12 +91,12 @@ describe("ArtifactGlobber", () => {
}) })
function createArtifactGlobber(results: string[] = globResults): FileArtifactGlobber { function createArtifactGlobber(results: string[] = globResults): FileArtifactGlobber {
const MockGlobber = jest.fn<Globber, any>(() => { const MockGlobber = vi.fn<() => Globber>(() => {
return { return {
glob: globMock, glob: globMock,
} }
}) })
globMock.mockReturnValue(results) globMock.mockReturnValue(results)
return new FileArtifactGlobber(new MockGlobber()) return new FileArtifactGlobber(MockGlobber())
} }
}) })

View File

@@ -1,22 +1,21 @@
const directoryMock = jest.fn() import * as fs from "node:fs"
const warnMock = jest.fn() import * as core from "@actions/core"
import { describe, expect, it, vi } from "vitest"
import { ArtifactPathValidator } from "../src/ArtifactPathValidator" vi.mock("@actions/core")
vi.mock("fs")
import { ArtifactPathValidator } from "../src/ArtifactPathValidator.js"
const warnMock = vi.mocked(core.warning)
const mockStatSync = vi.mocked(fs.statSync)
const directoryMock = vi.fn()
// biome-ignore lint/suspicious/noExplicitAny: Partial Stats object for testing
mockStatSync.mockReturnValue({ isDirectory: directoryMock } as any)
const pattern = "pattern" const pattern = "pattern"
jest.mock("@actions/core", () => {
return { warning: warnMock }
})
jest.mock("fs", () => {
return {
statSync: () => {
return { isDirectory: directoryMock }
},
}
})
describe("ArtifactPathValidator", () => { describe("ArtifactPathValidator", () => {
beforeEach(() => { beforeEach(() => {
warnMock.mockClear() warnMock.mockClear()
@@ -36,7 +35,7 @@ describe("ArtifactPathValidator", () => {
it("warns when no glob results are produced and empty results shouldn't throw", () => { it("warns when no glob results are produced and empty results shouldn't throw", () => {
const validator = new ArtifactPathValidator(false, [], pattern) const validator = new ArtifactPathValidator(false, [], pattern)
const result = validator.validate() const _result = validator.validate()
expect(warnMock).toHaveBeenCalled() expect(warnMock).toHaveBeenCalled()
}) })

View File

@@ -1,7 +1,8 @@
import { RequestError } from "@octokit/request-error" import { RequestError } from "@octokit/request-error"
import { Artifact } from "../src/Artifact" import { beforeEach, describe, expect, it, vi } from "vitest"
import { GithubArtifactUploader } from "../src/ArtifactUploader" import { Artifact } from "../src/Artifact.js"
import type { Releases } from "../src/Releases" import { GithubArtifactUploader } from "../src/ArtifactUploader.js"
import type { Releases } from "../src/Releases.js"
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")] const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
const fakeReadStream = {} const fakeReadStream = {}
@@ -9,9 +10,9 @@ const contentLength = 42
const releaseId = 100 const releaseId = 100
const url = "http://api.example.com" const url = "http://api.example.com"
const deleteMock = jest.fn() const deleteMock = vi.fn()
const listArtifactsMock = jest.fn() const listArtifactsMock = vi.fn()
const uploadMock = jest.fn() const uploadMock = vi.fn()
// Mock response with browser_download_url // Mock response with browser_download_url
const mockUploadResponse = (name: string) => ({ const mockUploadResponse = (name: string) => ({
@@ -19,11 +20,11 @@ const mockUploadResponse = (name: string) => ({
browser_download_url: `https://github.com/octocat/Hello-World/releases/download/v1.0.0/${name}`, browser_download_url: `https://github.com/octocat/Hello-World/releases/download/v1.0.0/${name}`,
name: name, name: name,
id: 1, id: 1,
} },
}) })
jest.mock("fs", () => { vi.mock("fs", async () => {
const originalFs = jest.requireActual("fs") const originalFs = await vi.importActual<typeof import("fs")>("fs")
return { return {
...originalFs, ...originalFs,
promises: {}, promises: {},
@@ -49,8 +50,8 @@ describe("ArtifactUploader", () => {
const result = await uploader.uploadArtifacts(artifacts, releaseId, url) const result = await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(result).toEqual({ expect(result).toEqual({
"art1": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1", art1: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1",
"art2": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2", art2: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2",
}) })
expect(uploadMock).toHaveBeenCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
}) })
@@ -117,8 +118,8 @@ describe("ArtifactUploader", () => {
const result = await uploader.uploadArtifacts(artifacts, releaseId, url) const result = await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(result).toEqual({ expect(result).toEqual({
"art1": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1", art1: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1",
"art2": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2", art2: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2",
}) })
expect(uploadMock).toHaveBeenCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
@@ -138,8 +139,8 @@ describe("ArtifactUploader", () => {
const result = await uploader.uploadArtifacts(artifacts, releaseId, url) const result = await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(result).toEqual({ expect(result).toEqual({
"art1": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1", art1: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1",
"art2": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2", art2: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2",
}) })
expect(uploadMock).toHaveBeenCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
@@ -201,8 +202,8 @@ describe("ArtifactUploader", () => {
const result = await uploader.uploadArtifacts(artifacts, releaseId, url) const result = await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(result).toEqual({ expect(result).toEqual({
"art1": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1", art1: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art1",
"art2": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2", art2: "https://github.com/octocat/Hello-World/releases/download/v1.0.0/art2",
}) })
expect(uploadMock).toHaveBeenCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
@@ -212,26 +213,26 @@ describe("ArtifactUploader", () => {
}) })
function createUploader(replaces: boolean, throws = false): GithubArtifactUploader { function createUploader(replaces: boolean, throws = false): GithubArtifactUploader {
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = vi.fn<() => Releases>(() => {
return { return {
create: jest.fn(), create: vi.fn(),
deleteArtifact: deleteMock, deleteArtifact: deleteMock,
getByTag: jest.fn(), getByTag: vi.fn(),
listArtifactsForRelease: listArtifactsMock, listArtifactsForRelease: listArtifactsMock,
listReleases: jest.fn(), listReleases: vi.fn(),
update: jest.fn(), update: vi.fn(),
uploadArtifact: uploadMock, uploadArtifact: uploadMock,
generateReleaseNotes: jest.fn(), generateReleaseNotes: vi.fn(),
} }
}) })
return new GithubArtifactUploader(new MockReleases(), replaces, throws) return new GithubArtifactUploader(MockReleases(), replaces, throws)
} }
function mockDeleteError(): any { function mockDeleteError(): void {
deleteMock.mockRejectedValue("error") deleteMock.mockRejectedValue("error")
} }
function mockDeleteSuccess(): any { function mockDeleteSuccess(): void {
deleteMock.mockResolvedValue({}) deleteMock.mockResolvedValue({})
} }

View File

@@ -1,4 +1,5 @@
import { GithubError } from "../src/GithubError" import { describe, expect, it } from "vitest"
import { GithubError } from "../src/GithubError.js"
describe("ErrorMessage", () => { describe("ErrorMessage", () => {
describe("has error with code", () => { describe("has error with code", () => {

View File

@@ -1,4 +1,5 @@
import { GithubErrorDetail } from "../src/GithubErrorDetail" import { describe, expect, it } from "vitest"
import { GithubErrorDetail } from "../src/GithubErrorDetail.js"
describe("GithubErrorDetail", () => { describe("GithubErrorDetail", () => {
it("provides error code", () => { it("provides error code", () => {

View File

@@ -1,41 +1,56 @@
const mockGetInput = jest.fn() import * as fs from "node:fs"
const mockGetBooleanInput = jest.fn() import * as core from "@actions/core"
const mockGlob = jest.fn() import type * as github from "@actions/github"
const mockReadFileSync = jest.fn() import { beforeEach, describe, expect, it, vi } from "vitest"
const mockStatSync = jest.fn()
import { Artifact } from "../src/Artifact" vi.mock("@actions/core")
import { ArtifactGlobber } from "../src/ArtifactGlobber" vi.mock("fs")
import { Context } from "@actions/github/lib/context"
import { Inputs, CoreInputs } from "../src/Inputs" import { Artifact } from "../src/Artifact.js"
import type { ArtifactGlobber } from "../src/ArtifactGlobber.js"
import { CoreInputs, type Inputs } from "../src/Inputs.js"
const mockGetInput = vi.mocked(core.getInput)
const mockGetBooleanInput = vi.mocked(core.getBooleanInput)
const mockReadFileSync = vi.mocked(fs.readFileSync)
const _mockStatSync = vi.mocked(fs.statSync)
const mockExistsSync = vi.mocked(fs.existsSync)
const mockGlob = vi.fn()
// existsSync is used by Context's constructor
mockExistsSync.mockReturnValue(false)
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")] const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
jest.mock("@actions/core", () => {
return {
getInput: mockGetInput,
getBooleanInput: mockGetBooleanInput,
}
})
jest.mock("fs", () => {
// existsSync is used by Context's constructor
// noinspection JSUnusedGlobalSymbols
return {
existsSync: () => {
return false
},
readFileSync: mockReadFileSync,
statSync: mockStatSync,
}
})
describe("Inputs", () => { describe("Inputs", () => {
let context: Context let context: typeof github.context
let inputs: Inputs let inputs: Inputs
beforeEach(() => { beforeEach(() => {
mockGetInput.mockReset() mockGetInput.mockReset()
context = new Context() mockGlob.mockClear()
context = {
payload: {},
eventName: "",
sha: "",
ref: "",
workflow: "",
action: "",
actor: "",
job: "",
runNumber: 0,
runId: 0,
runAttempt: 0,
apiUrl: "",
serverUrl: "",
graphqlUrl: "",
get repo() {
const repo = process.env.GITHUB_REPOSITORY || "/"
const [owner, repoName] = repo.split("/")
return { owner: owner || "", repo: repoName || "" }
},
issue: { owner: "", repo: "", number: 0 },
// biome-ignore lint/suspicious/noExplicitAny: Partial Context object for testing
} as any
inputs = new CoreInputs(createGlobber(), context) inputs = new CoreInputs(createGlobber(), context)
}) })
@@ -189,41 +204,41 @@ describe("Inputs", () => {
}) })
describe("generateReleaseNotes", () => { describe("generateReleaseNotes", () => {
it("returns returns true", function () { it("returns returns true", () => {
mockGetInput.mockReturnValue("true") mockGetInput.mockReturnValue("true")
expect(inputs.generateReleaseNotes).toBe(true) expect(inputs.generateReleaseNotes).toBe(true)
}) })
it("returns false when omitted", function () { it("returns false when omitted", () => {
mockGetInput.mockReturnValue("") mockGetInput.mockReturnValue("")
expect(inputs.generateReleaseNotes).toBe(false) expect(inputs.generateReleaseNotes).toBe(false)
}) })
}) })
describe("generateReleaseNotesPreviousTag", () => { describe("generateReleaseNotesPreviousTag", () => {
it("returns the previous tag when provided", function () { it("returns the previous tag when provided", () => {
mockGetInput.mockReturnValue("v1.0.0") mockGetInput.mockReturnValue("v1.0.0")
expect(inputs.generateReleaseNotesPreviousTag).toBe("v1.0.0") expect(inputs.generateReleaseNotesPreviousTag).toBe("v1.0.0")
}) })
it("returns undefined when omitted", function () { it("returns undefined when omitted", () => {
mockGetInput.mockReturnValue("") mockGetInput.mockReturnValue("")
expect(inputs.generateReleaseNotesPreviousTag).toBeUndefined() expect(inputs.generateReleaseNotesPreviousTag).toBeUndefined()
}) })
}) })
describe("immutableCreate", () => { describe("immutableCreate", () => {
it("returns false by default", function () { it("returns false by default", () => {
mockGetInput.mockReturnValue("") mockGetInput.mockReturnValue("")
expect(inputs.immutableCreate).toBe(false) expect(inputs.immutableCreate).toBe(false)
}) })
it("returns true when explicitly set", function () { it("returns true when explicitly set", () => {
mockGetInput.mockReturnValue("true") mockGetInput.mockReturnValue("true")
expect(inputs.immutableCreate).toBe(true) expect(inputs.immutableCreate).toBe(true)
}) })
it("returns false when explicitly disabled", function () { it("returns false when explicitly disabled", () => {
mockGetInput.mockReturnValue("false") mockGetInput.mockReturnValue("false")
expect(inputs.immutableCreate).toBe(false) expect(inputs.immutableCreate).toBe(false)
}) })
@@ -252,12 +267,12 @@ describe("Inputs", () => {
}) })
describe("owner", () => { describe("owner", () => {
it("returns owner from context", function () { it("returns owner from context", () => {
process.env.GITHUB_REPOSITORY = "owner/repo" process.env.GITHUB_REPOSITORY = "owner/repo"
mockGetInput.mockReturnValue("") mockGetInput.mockReturnValue("")
expect(inputs.owner).toBe("owner") expect(inputs.owner).toBe("owner")
}) })
it("returns owner from inputs", function () { it("returns owner from inputs", () => {
mockGetInput.mockReturnValue("owner") mockGetInput.mockReturnValue("owner")
expect(inputs.owner).toBe("owner") expect(inputs.owner).toBe("owner")
}) })
@@ -297,12 +312,12 @@ describe("Inputs", () => {
}) })
describe("repo", () => { describe("repo", () => {
it("returns repo from context", function () { it("returns repo from context", () => {
process.env.GITHUB_REPOSITORY = "owner/repo" process.env.GITHUB_REPOSITORY = "owner/repo"
mockGetInput.mockReturnValue("") mockGetInput.mockReturnValue("")
expect(inputs.repo).toBe("repo") expect(inputs.repo).toBe("repo")
}) })
it("returns repo from inputs", function () { it("returns repo from inputs", () => {
mockGetInput.mockReturnValue("repo") mockGetInput.mockReturnValue("repo")
expect(inputs.repo).toBe("repo") expect(inputs.repo).toBe("repo")
}) })
@@ -330,11 +345,6 @@ describe("Inputs", () => {
context.ref = "refs/tags/sha-tag" context.ref = "refs/tags/sha-tag"
expect(inputs.tag).toBe("sha-tag") expect(inputs.tag).toBe("sha-tag")
}) })
it("returns context sha when input is null", () => {
mockGetInput.mockReturnValue(null)
context.ref = "refs/tags/sha-tag"
expect(inputs.tag).toBe("sha-tag")
})
it("throws if no tag", () => { it("throws if no tag", () => {
context.ref = "" context.ref = ""
expect(() => inputs.tag).toThrow() expect(() => inputs.tag).toThrow()
@@ -462,12 +472,12 @@ describe("Inputs", () => {
}) })
function createGlobber(): ArtifactGlobber { function createGlobber(): ArtifactGlobber {
const MockGlobber = jest.fn<ArtifactGlobber, any>(() => { const MockGlobber = vi.fn<() => ArtifactGlobber>(() => {
return { return {
globArtifactString: mockGlob, globArtifactString: mockGlob,
} }
}) })
mockGlob.mockImplementation(() => artifacts) mockGlob.mockImplementation(() => artifacts)
return new MockGlobber() return MockGlobber()
} }
}) })

View File

@@ -1,13 +1,14 @@
import { Action } from "../src/Action" import * as path from "node:path"
import * as github from "@actions/github" import * as github from "@actions/github"
import { Inputs } from "../src/Inputs" import { beforeEach, describe, it, vi } from "vitest"
import { GithubReleases, ReleaseData } from "../src/Releases" import { Action } from "../src/Action.js"
import { GithubArtifactUploader } from "../src/ArtifactUploader" import { ReleaseActionSkipper } from "../src/ActionSkipper.js"
import * as path from "path" import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer.js"
import { FileArtifactGlobber } from "../src/ArtifactGlobber" import { FileArtifactGlobber } from "../src/ArtifactGlobber.js"
import { Outputs } from "../src/Outputs" import { GithubArtifactUploader } from "../src/ArtifactUploader.js"
import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer" import type { Inputs } from "../src/Inputs.js"
import { ReleaseActionSkipper } from "../src/ActionSkipper" import type { Outputs } from "../src/Outputs.js"
import { GithubReleases, type ReleaseData } from "../src/Releases.js"
// This test is currently intended to be manually run during development. To run: // This test is currently intended to be manually run during development. To run:
// - Make sure you have an environment variable named GITHUB_TOKEN assigned to your token // - Make sure you have an environment variable named GITHUB_TOKEN assigned to your token
@@ -34,7 +35,7 @@ describe.skip("Integration Test", () => {
}) })
function getInputs(): Inputs { function getInputs(): Inputs {
const MockInputs = jest.fn<Inputs, any>(() => { const MockInputs = vi.fn<() => Inputs>(() => {
return { return {
allowUpdates: true, allowUpdates: true,
artifactErrorsFailBuild: false, artifactErrorsFailBuild: false,
@@ -62,11 +63,11 @@ describe.skip("Integration Test", () => {
updateOnlyUnreleased: false, updateOnlyUnreleased: false,
} }
}) })
return new MockInputs() return MockInputs()
} }
function getOutputs(): Outputs { function getOutputs(): Outputs {
const MockOutputs = jest.fn<Outputs, any>(() => { const MockOutputs = vi.fn<() => Outputs>(() => {
return { return {
applyReleaseData(releaseData: ReleaseData) { applyReleaseData(releaseData: ReleaseData) {
console.log(`Release Data: ${releaseData}`) console.log(`Release Data: ${releaseData}`)
@@ -76,7 +77,7 @@ describe.skip("Integration Test", () => {
}, },
} }
}) })
return new MockOutputs() return MockOutputs()
} }
function artifacts() { function artifacts() {

View File

@@ -1,8 +1,10 @@
import { CoreOutputs, type Outputs } from "../src/Outputs" import * as core from "@actions/core"
import type { ReleaseData } from "../src/Releases" import { describe, expect, it, vi } from "vitest"
import { CoreOutputs, type Outputs } from "../src/Outputs.js"
import type { ReleaseData } from "../src/Releases.js"
jest.mock("@actions/core") vi.mock("@actions/core")
const { setOutput: mockSetOutput } = jest.mocked(require("@actions/core")) const mockSetOutput = vi.mocked(core.setOutput)
const TEST_URLS = { const TEST_URLS = {
HTML_URL: "https://api.example.com/assets", HTML_URL: "https://api.example.com/assets",

View File

@@ -1,5 +1,6 @@
import os from "os" import os from "node:os"
import { expandTilde } from "../src/PathExpander" import { describe, expect, it } from "vitest"
import { expandTilde } from "../src/PathExpander.js"
describe("PathExpander", () => { describe("PathExpander", () => {
describe("expandTilde", () => { describe("expandTilde", () => {
@@ -39,4 +40,3 @@ describe("PathExpander", () => {
}) })
}) })
}) })

View File

@@ -1,4 +1,5 @@
import { ReleaseValidator } from "../src/ReleaseValidator" import { describe, expect, it } from "vitest"
import { ReleaseValidator } from "../src/ReleaseValidator.js"
describe("validateReleaseUpdate", () => { describe("validateReleaseUpdate", () => {
describe("updateOnlyUnreleased is disabled", () => { describe("updateOnlyUnreleased is disabled", () => {

View File

@@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "$schema": "https://biomejs.dev/schemas/2.3.13/schema.json",
"vcs": { "vcs": {
"enabled": false, "enabled": false,
"clientKind": "git", "clientKind": "git",
@@ -7,7 +7,7 @@
}, },
"files": { "files": {
"ignoreUnknown": false, "ignoreUnknown": false,
"ignore": ["node_modules/**/*", "dist/"] "includes": ["**", "!**/node_modules/**/*", "!**/dist/"]
}, },
"formatter": { "formatter": {
"enabled": true, "enabled": true,
@@ -17,9 +17,9 @@
"indentWidth": 4, "indentWidth": 4,
"lineWidth": 120 "lineWidth": 120
}, },
"organizeImports": { "enabled": true }, "assist": { "actions": { "source": { "organizeImports": "on" } } },
"linter": { "linter": {
"enabled": false, "enabled": true,
"rules": { "rules": {
"recommended": true "recommended": true
} }

43250
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

310
dist/licenses.txt vendored
View File

@@ -93,6 +93,60 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE. IN THE SOFTWARE.
@isaacs/balanced-match
MIT
(MIT)
Original code Copyright Julian Gruber <julian@juliangruber.com>
Port to TypeScript Copyright Isaac Z. Schlueter <i@izs.me>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@isaacs/brace-expansion
MIT
MIT License
Copyright Julian Gruber <julian@juliangruber.com>
TypeScript port Copyright Isaac Z. Schlueter <i@izs.me>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@octokit/auth-token @octokit/auth-token
MIT MIT
The MIT License The MIT License
@@ -265,31 +319,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
balanced-match
MIT
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
before-after-hook before-after-hook
Apache-2.0 Apache-2.0
Apache License Apache License
@@ -495,31 +524,6 @@ Apache-2.0
limitations under the License. limitations under the License.
brace-expansion
MIT
MIT License
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
deprecation deprecation
ISC ISC
The ISC License The ISC License
@@ -540,60 +544,188 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
glob glob
ISC BlueOak-1.0.0
The ISC License All packages under `src/` are licensed according to the terms in
their respective `LICENSE` or `LICENSE.md` files.
Copyright (c) 2009-2023 Isaac Z. Schlueter and Contributors The remainder of this project is licensed under the Blue Oak
Model License, as follows:
Permission to use, copy, modify, and/or distribute this software for any -----
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # Blue Oak Model License
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR Version 1.0.0
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ## Purpose
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. This license gives everyone as much permission to work with
this software as possible, while protecting contributors
from liability.
## Acceptance
In order to receive this license, you must agree to its
rules. The rules of this license are both obligations
under that agreement and conditions to your license.
You must not do anything with this software that triggers
a rule that you cannot or will not follow.
## Copyright
Each contributor licenses you to do everything with this
software that would otherwise infringe that contributor's
copyright in it.
## Notices
You must ensure that everyone who gets a copy of
any part of this software from you, with or without
changes, also gets the text of this license or a link to
<https://blueoakcouncil.org/license/1.0.0>.
## Excuse
If anyone notifies you in writing that you have not
complied with [Notices](#notices), you can keep your
license by taking all practical steps to comply within 30
days after the notice. If you do not do so, your license
ends immediately.
## Patent
Each contributor licenses you to do everything with this
software that would otherwise infringe any patent claims
they can license or become able to license.
## Reliability
No contributor can revoke this license.
## No Liability
***As far as the law allows, this software comes as is,
without any warranty or condition, and no contributor
will be liable to anyone for any damages related to this
software or this license, under any kind of legal claim.***
lru-cache lru-cache
ISC BlueOak-1.0.0
The ISC License # Blue Oak Model License
Copyright (c) 2010-2023 Isaac Z. Schlueter and Contributors Version 1.0.0
Permission to use, copy, modify, and/or distribute this software for any ## Purpose
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES This license gives everyone as much permission to work with
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF this software as possible, while protecting contributors
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR from liability.
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ## Acceptance
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. In order to receive this license, you must agree to its
rules. The rules of this license are both obligations
under that agreement and conditions to your license.
You must not do anything with this software that triggers
a rule that you cannot or will not follow.
## Copyright
Each contributor licenses you to do everything with this
software that would otherwise infringe that contributor's
copyright in it.
## Notices
You must ensure that everyone who gets a copy of
any part of this software from you, with or without
changes, also gets the text of this license or a link to
<https://blueoakcouncil.org/license/1.0.0>.
## Excuse
If anyone notifies you in writing that you have not
complied with [Notices](#notices), you can keep your
license by taking all practical steps to comply within 30
days after the notice. If you do not do so, your license
ends immediately.
## Patent
Each contributor licenses you to do everything with this
software that would otherwise infringe any patent claims
they can license or become able to license.
## Reliability
No contributor can revoke this license.
## No Liability
***As far as the law allows, this software comes as is,
without any warranty or condition, and no contributor
will be liable to anyone for any damages related to this
software or this license, under any kind of legal claim.***
minimatch minimatch
ISC BlueOak-1.0.0
The ISC License # Blue Oak Model License
Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors Version 1.0.0
Permission to use, copy, modify, and/or distribute this software for any ## Purpose
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES This license gives everyone as much permission to work with
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF this software as possible, while protecting contributors
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR from liability.
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ## Acceptance
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. In order to receive this license, you must agree to its
rules. The rules of this license are both obligations
under that agreement and conditions to your license.
You must not do anything with this software that triggers
a rule that you cannot or will not follow.
## Copyright
Each contributor licenses you to do everything with this
software that would otherwise infringe that contributor's
copyright in it.
## Notices
You must ensure that everyone who gets a copy of
any part of this software from you, with or without
changes, also gets the text of this license or a link to
<https://blueoakcouncil.org/license/1.0.0>.
## Excuse
If anyone notifies you in writing that you have not
complied with [Notices](#notices), you can keep your
license by taking all practical steps to comply within 30
days after the notice. If you do not do so, your license
ends immediately.
## Patent
Each contributor licenses you to do everything with this
software that would otherwise infringe any patent claims
they can license or become able to license.
## Reliability
No contributor can revoke this license.
## No Liability
**_As far as the law allows, this software comes as is,
without any warranty or condition, and no contributor
will be liable to anyone for any damages related to this
software or this license, under any kind of legal claim._**
minipass minipass

3
dist/package.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"type": "module"
}

1
dist/sourcemap-register.cjs vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,54 +1,36 @@
{ {
"name": "release-action", "name": "release-action",
"version": "1.1.0", "version": "1.1.0",
"type": "module",
"private": true, "private": true,
"description": "An action which manages a github release", "description": "An action which manages a github release",
"main": "lib/main.js", "main": "lib/src/Main.js",
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"clean": "rm -rf lib/*", "clean": "rm -rf lib/*",
"coverage": "jest --coverage", "coverage": "vitest run --coverage",
"debug": "pnpm clean && pnpm install && pnpm build && pnpm package", "debug": "pnpm clean && pnpm install && pnpm build && pnpm package",
"format": "pnpm biome format --write .", "format": "pnpm biome format --write .",
"package": "ncc build --source-map --license licenses.txt", "package": "ncc build --source-map --license licenses.txt",
"release": "pnpm clean && pnpm install --prod && pnpm build && pnpm package", "release": "pnpm clean && pnpm install --prod && pnpm build && pnpm package",
"test": "jest" "test": "vitest run"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/ncipollo/release-action.git" "url": "git+https://github.com/ncipollo/release-action.git"
}, },
"keywords": ["actions", "node", "setup"], "keywords": [
"actions",
"node",
"setup"
],
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=20" "node": ">=20"
}, },
"jest": {
"clearMocks": true,
"collectCoverage": true,
"coveragePathIgnorePatterns": ["src/Globber.ts", "src/Releases.ts"],
"coverageThreshold": {
"global": {
"branches": 95,
"functions": 100,
"lines": 100,
"statements": 100
}
},
"moduleFileExtensions": ["js", "ts"],
"testEnvironment": "node",
"testMatch": ["**/*.test.ts"],
"testRunner": "jest-circus/runner",
"transform": {
"^.+\\.ts$": ["ts-jest", {
"tsconfig": "tsconfig.test.json"
}]
},
"verbose": true
},
"dependencies": { "dependencies": {
"@actions/core": "^2.0.1", "@actions/core": "^3.0.0",
"@actions/github": "^6.0.1", "@actions/github": "^6.0.1",
"@types/node": "^25.1.0", "@types/node": "^25.1.0",
"glob": "^13.0.0" "glob": "^13.0.0"
@@ -56,19 +38,10 @@
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.3.13", "@biomejs/biome": "2.3.13",
"@octokit/plugin-rest-endpoint-methods": "^10.4.1", "@octokit/plugin-rest-endpoint-methods": "^10.4.1",
"@octokit/request-error": "^7.1.0",
"@octokit/types": "^16.0.0", "@octokit/types": "^16.0.0",
"@types/jest": "30.0.0", "@vitest/coverage-v8": "^4.0.18",
"jest": "^30.2.0", "typescript": "^5.9.3",
"jest-circus": "^30.2.0", "vitest": "^4.0.18"
"ts-jest": "^29.4.5",
"typescript": "^5.9.3"
},
"pnpm": {
"overrides": {
"jest-cli>yargs": "^17.3.1",
"glob": "^10.5.0",
"test-exclude": "^7.0.0",
"babel-plugin-istanbul": "^7.0.0"
}
} }
} }

3411
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,18 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import type { ActionSkipper } from "./ActionSkipper" import type { ActionSkipper } from "./ActionSkipper.js"
import type { ArtifactDestroyer } from "./ArtifactDestroyer" import type { ArtifactDestroyer } from "./ArtifactDestroyer.js"
import type { ArtifactUploader } from "./ArtifactUploader" import type { ArtifactUploader } from "./ArtifactUploader.js"
import { GithubError } from "./GithubError" import { GithubError } from "./GithubError.js"
import type { Inputs } from "./Inputs" import type { Inputs } from "./Inputs.js"
import type { Outputs } from "./Outputs" import type { Outputs } from "./Outputs.js"
import { ReleaseValidator } from "./ReleaseValidator" import { ReleaseValidator } from "./ReleaseValidator.js"
import type { import type {
CreateOrUpdateReleaseResponse, CreateOrUpdateReleaseResponse,
CreateReleaseResponse, CreateReleaseResponse,
ReleaseByTagResponse, ReleaseByTagResponse,
Releases, Releases,
UpdateReleaseResponse, UpdateReleaseResponse,
} from "./Releases" } from "./Releases.js"
export class Action { export class Action {
private inputs: Inputs private inputs: Inputs

View File

@@ -1,4 +1,4 @@
import { Releases } from "./Releases" import { Releases } from "./Releases.js"
export interface ActionSkipper { export interface ActionSkipper {
shouldSkip(): Promise<boolean> shouldSkip(): Promise<boolean>

View File

@@ -1,4 +1,4 @@
import { Releases } from "./Releases" import { Releases } from "./Releases.js"
import * as core from "@actions/core" import * as core from "@actions/core"
export interface ArtifactDestroyer { export interface ArtifactDestroyer {

View File

@@ -1,9 +1,9 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import { Globber, FileGlobber } from "./Globber" import { Globber, FileGlobber } from "./Globber.js"
import { Artifact } from "./Artifact" import { Artifact } from "./Artifact.js"
import { expandTilde } from "./PathExpander" import { expandTilde } from "./PathExpander.js"
import { ArtifactPathValidator } from "./ArtifactPathValidator" import { ArtifactPathValidator } from "./ArtifactPathValidator.js"
import { PathNormalizer } from "./PathNormalizer" import { PathNormalizer } from "./PathNormalizer.js"
export interface ArtifactGlobber { export interface ArtifactGlobber {
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[] globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[]

View File

@@ -1,6 +1,6 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import { Artifact } from "./Artifact" import { Artifact } from "./Artifact.js"
import { Releases } from "./Releases" import { Releases } from "./Releases.js"
export interface ArtifactUploader { export interface ArtifactUploader {
uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<Record<string, string>> uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<Record<string, string>>

View File

@@ -1,4 +1,4 @@
import { GithubErrorDetail } from "./GithubErrorDetail" import { GithubErrorDetail } from "./GithubErrorDetail.js"
export class GithubError { export class GithubError {
private error: any private error: any

View File

@@ -1,8 +1,8 @@
import { readFileSync } from "node:fs"
import * as core from "@actions/core" import * as core from "@actions/core"
import { Context } from "@actions/github/lib/context" import type * as github from "@actions/github"
import { readFileSync } from "fs" import type { Artifact } from "./Artifact.js"
import { ArtifactGlobber } from "./ArtifactGlobber" import type { ArtifactGlobber } from "./ArtifactGlobber.js"
import { Artifact } from "./Artifact"
export interface Inputs { export interface Inputs {
readonly allowUpdates: boolean readonly allowUpdates: boolean
@@ -35,16 +35,16 @@ export interface Inputs {
export class CoreInputs implements Inputs { export class CoreInputs implements Inputs {
private artifactGlobber: ArtifactGlobber private artifactGlobber: ArtifactGlobber
private context: Context private context: typeof github.context
constructor(artifactGlobber: ArtifactGlobber, context: Context) { constructor(artifactGlobber: ArtifactGlobber, context: typeof github.context) {
this.artifactGlobber = artifactGlobber this.artifactGlobber = artifactGlobber
this.context = context this.context = context
} }
get allowUpdates(): boolean { get allowUpdates(): boolean {
const allow = core.getInput("allowUpdates") const allow = core.getInput("allowUpdates")
return allow == "true" return allow === "true"
} }
get artifacts(): Artifact[] { get artifacts(): Artifact[] {
@@ -64,7 +64,7 @@ export class CoreInputs implements Inputs {
get artifactErrorsFailBuild(): boolean { get artifactErrorsFailBuild(): boolean {
const allow = core.getInput("artifactErrorsFailBuild") const allow = core.getInput("artifactErrorsFailBuild")
return allow == "true" return allow === "true"
} }
private get body(): string | undefined { private get body(): string | undefined {
@@ -83,12 +83,12 @@ export class CoreInputs implements Inputs {
get createdDraft(): boolean { get createdDraft(): boolean {
const draft = core.getInput("draft") const draft = core.getInput("draft")
return draft == "true" return draft === "true"
} }
get createdPrerelease(): boolean { get createdPrerelease(): boolean {
const preRelease = core.getInput("prerelease") const preRelease = core.getInput("prerelease")
return preRelease == "true" return preRelease === "true"
} }
get createdReleaseBody(): string | undefined { get createdReleaseBody(): string | undefined {
@@ -97,7 +97,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitBody(): boolean { private static get omitBody(): boolean {
return core.getInput("omitBody") == "true" return core.getInput("omitBody") === "true"
} }
get createdReleaseName(): string | undefined { get createdReleaseName(): string | undefined {
@@ -106,7 +106,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitName(): boolean { private static get omitName(): boolean {
return core.getInput("omitName") == "true" return core.getInput("omitName") === "true"
} }
get commit(): string | undefined { get commit(): string | undefined {
@@ -136,7 +136,7 @@ export class CoreInputs implements Inputs {
get generateReleaseNotes(): boolean { get generateReleaseNotes(): boolean {
const generate = core.getInput("generateReleaseNotes") const generate = core.getInput("generateReleaseNotes")
return generate == "true" return generate === "true"
} }
get generateReleaseNotesPreviousTag(): string | undefined { get generateReleaseNotesPreviousTag(): string | undefined {
@@ -146,12 +146,12 @@ export class CoreInputs implements Inputs {
get immutableCreate(): boolean { get immutableCreate(): boolean {
const immutable = core.getInput("immutableCreate") const immutable = core.getInput("immutableCreate")
return immutable == "true" return immutable === "true"
} }
get makeLatest(): "legacy" | "true" | "false" | undefined { get makeLatest(): "legacy" | "true" | "false" | undefined {
let latest = core.getInput("makeLatest") const latest = core.getInput("makeLatest")
if (latest == "true" || latest == "false" || latest == "legacy") { if (latest === "true" || latest === "false" || latest === "legacy") {
return latest return latest
} }
@@ -159,7 +159,7 @@ export class CoreInputs implements Inputs {
} }
get owner(): string { get owner(): string {
let owner = core.getInput("owner") const owner = core.getInput("owner")
if (owner) { if (owner) {
return owner return owner
} }
@@ -168,16 +168,16 @@ export class CoreInputs implements Inputs {
get removeArtifacts(): boolean { get removeArtifacts(): boolean {
const removes = core.getInput("removeArtifacts") const removes = core.getInput("removeArtifacts")
return removes == "true" return removes === "true"
} }
get replacesArtifacts(): boolean { get replacesArtifacts(): boolean {
const replaces = core.getInput("replacesArtifacts") const replaces = core.getInput("replacesArtifacts")
return replaces == "true" return replaces === "true"
} }
get repo(): string { get repo(): string {
let repo = core.getInput("repo") const repo = core.getInput("repo")
if (repo) { if (repo) {
return repo return repo
} }
@@ -196,7 +196,7 @@ export class CoreInputs implements Inputs {
const ref = this.context.ref const ref = this.context.ref
const tagPath = "refs/tags/" const tagPath = "refs/tags/"
if (ref && ref.startsWith(tagPath)) { if (ref?.startsWith(tagPath)) {
return ref.substr(tagPath.length, ref.length) return ref.substr(tagPath.length, ref.length)
} }
@@ -213,7 +213,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitDraftDuringUpdate(): boolean { private static get omitDraftDuringUpdate(): boolean {
return core.getInput("omitDraftDuringUpdate") == "true" return core.getInput("omitDraftDuringUpdate") === "true"
} }
get updatedPrerelease(): boolean | undefined { get updatedPrerelease(): boolean | undefined {
@@ -222,7 +222,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitPrereleaseDuringUpdate(): boolean { private static get omitPrereleaseDuringUpdate(): boolean {
return core.getInput("omitPrereleaseDuringUpdate") == "true" return core.getInput("omitPrereleaseDuringUpdate") === "true"
} }
get updatedReleaseBody(): string | undefined { get updatedReleaseBody(): string | undefined {
@@ -231,7 +231,7 @@ export class CoreInputs implements Inputs {
} }
get updateOnlyUnreleased(): boolean { get updateOnlyUnreleased(): boolean {
return core.getInput("updateOnlyUnreleased") == "true" return core.getInput("updateOnlyUnreleased") === "true"
} }
get updatedReleaseName(): string | undefined { get updatedReleaseName(): string | undefined {
@@ -240,7 +240,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitBodyDuringUpdate(): boolean { private static get omitBodyDuringUpdate(): boolean {
return core.getInput("omitBodyDuringUpdate") == "true" return core.getInput("omitBodyDuringUpdate") === "true"
} }
get omitBodyDuringUpdate(): boolean { get omitBodyDuringUpdate(): boolean {
@@ -248,7 +248,7 @@ export class CoreInputs implements Inputs {
} }
private static get omitNameDuringUpdate(): boolean { private static get omitNameDuringUpdate(): boolean {
return core.getInput("omitNameDuringUpdate") == "true" return core.getInput("omitNameDuringUpdate") === "true"
} }
stringFromFile(path: string): string { stringFromFile(path: string): string {

View File

@@ -1,14 +1,14 @@
import * as github from "@actions/github" import * as github from "@actions/github"
import * as core from "@actions/core" import * as core from "@actions/core"
import { CoreInputs } from "./Inputs" import { CoreInputs } from "./Inputs.js"
import { GithubReleases } from "./Releases" import { GithubReleases } from "./Releases.js"
import { Action } from "./Action" import { Action } from "./Action.js"
import { GithubArtifactUploader } from "./ArtifactUploader" import { GithubArtifactUploader } from "./ArtifactUploader.js"
import { FileArtifactGlobber } from "./ArtifactGlobber" import { FileArtifactGlobber } from "./ArtifactGlobber.js"
import { GithubError } from "./GithubError" import { GithubError } from "./GithubError.js"
import { CoreOutputs } from "./Outputs" import { CoreOutputs } from "./Outputs.js"
import { GithubArtifactDestroyer } from "./ArtifactDestroyer" import { GithubArtifactDestroyer } from "./ArtifactDestroyer.js"
import { ActionSkipper, ReleaseActionSkipper } from "./ActionSkipper" import { ActionSkipper, ReleaseActionSkipper } from "./ActionSkipper.js"
async function run() { async function run() {
try { try {

View File

@@ -1,5 +1,5 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import { ReleaseData } from "./Releases" import { ReleaseData } from "./Releases.js"
export interface Outputs { export interface Outputs {
applyReleaseData(releaseData: ReleaseData): void applyReleaseData(releaseData: ReleaseData): void

View File

@@ -1,7 +1,7 @@
import type { GitHub } from "@actions/github/lib/utils" import * as github from "@actions/github"
import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods" import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods"
import type { OctokitResponse } from "@octokit/types" import type { OctokitResponse } from "@octokit/types"
import type { Inputs } from "./Inputs" import type { Inputs } from "./Inputs.js"
export type CreateReleaseResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"] export type CreateReleaseResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"]
export type ReleaseByTagResponse = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"] export type ReleaseByTagResponse = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"]
@@ -65,10 +65,10 @@ export interface Releases {
} }
export class GithubReleases implements Releases { export class GithubReleases implements Releases {
git: InstanceType<typeof GitHub> git: ReturnType<typeof github.getOctokit>
inputs: Inputs inputs: Inputs
constructor(inputs: Inputs, git: InstanceType<typeof GitHub>) { constructor(inputs: Inputs, git: ReturnType<typeof github.getOctokit>) {
this.inputs = inputs this.inputs = inputs
this.git = git this.git = git
} }

21
vitest.config.ts Normal file
View File

@@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
include: ['**/*.test.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
include: ['src/**/*.ts'],
exclude: ['src/Globber.ts', 'src/Releases.ts'],
thresholds: {
lines: 100,
functions: 100,
branches: 95,
statements: 100,
},
},
},
})