Add biome and initial format rules
This commit is contained in:
6
.idea/biome.xml
generated
Normal file
6
.idea/biome.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BiomeSettings">
|
||||
<option name="enableLspFormat" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,11 +1,11 @@
|
||||
import {Action} from "../src/Action";
|
||||
import {Artifact} from "../src/Artifact";
|
||||
import {Inputs} from "../src/Inputs";
|
||||
import {Releases} from "../src/Releases";
|
||||
import {ArtifactUploader} from "../src/ArtifactUploader";
|
||||
import {Outputs} from "../src/Outputs";
|
||||
import {ArtifactDestroyer} from "../src/ArtifactDestroyer";
|
||||
import {ActionSkipper} from "../src/ActionSkipper";
|
||||
import { Action } from "../src/Action"
|
||||
import { Artifact } from "../src/Artifact"
|
||||
import { Inputs } from "../src/Inputs"
|
||||
import { Releases } from "../src/Releases"
|
||||
import { ArtifactUploader } from "../src/ArtifactUploader"
|
||||
import { Outputs } from "../src/Outputs"
|
||||
import { ArtifactDestroyer } from "../src/ArtifactDestroyer"
|
||||
import { ActionSkipper } from "../src/ActionSkipper"
|
||||
|
||||
const applyReleaseDataMock = jest.fn()
|
||||
const artifactDestroyMock = jest.fn()
|
||||
@@ -18,30 +18,27 @@ const shouldSkipMock = jest.fn()
|
||||
const updateMock = jest.fn()
|
||||
const uploadMock = jest.fn()
|
||||
|
||||
const artifacts = [
|
||||
new Artifact('a/art1'),
|
||||
new Artifact('b/art2')
|
||||
]
|
||||
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
|
||||
|
||||
const createBody = 'createBody'
|
||||
const createBody = "createBody"
|
||||
const createDraft = true
|
||||
const createName = 'createName'
|
||||
const commit = 'commit'
|
||||
const discussionCategory = 'discussionCategory'
|
||||
const createName = "createName"
|
||||
const commit = "commit"
|
||||
const discussionCategory = "discussionCategory"
|
||||
const generateReleaseNotes = true
|
||||
const id = 100
|
||||
const createPrerelease = true
|
||||
const releaseId = 101
|
||||
const replacesArtifacts = true
|
||||
const tag = 'tag'
|
||||
const token = 'token'
|
||||
const updateBody = 'updateBody'
|
||||
const tag = "tag"
|
||||
const token = "token"
|
||||
const updateBody = "updateBody"
|
||||
const updateDraft = false
|
||||
const updateName = 'updateName'
|
||||
const updateName = "updateName"
|
||||
const updatePrerelease = false
|
||||
const updateOnlyUnreleased = false
|
||||
const url = 'http://api.example.com'
|
||||
const makeLatest = 'legacy'
|
||||
const url = "http://api.example.com"
|
||||
const makeLatest = "legacy"
|
||||
|
||||
describe("Action", () => {
|
||||
beforeEach(() => {
|
||||
@@ -53,12 +50,13 @@ describe("Action", () => {
|
||||
uploadMock.mockClear()
|
||||
})
|
||||
|
||||
it('creates release but does not upload if no artifact', async () => {
|
||||
it("creates release but does not upload if no artifact", async () => {
|
||||
const action = createAction(false, false)
|
||||
|
||||
await action.perform()
|
||||
|
||||
expect(createMock).toBeCalledWith(tag,
|
||||
expect(createMock).toBeCalledWith(
|
||||
tag,
|
||||
createBody,
|
||||
commit,
|
||||
discussionCategory,
|
||||
@@ -66,14 +64,15 @@ describe("Action", () => {
|
||||
generateReleaseNotes,
|
||||
makeLatest,
|
||||
createName,
|
||||
createPrerelease)
|
||||
createPrerelease
|
||||
)
|
||||
expect(uploadMock).not.toBeCalled()
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('creates release if no release exists to update', async () => {
|
||||
it("creates release if no release exists to update", async () => {
|
||||
const action = createAction(true, true)
|
||||
const error = {status: 404}
|
||||
const error = { status: 404 }
|
||||
getMock.mockRejectedValue(error)
|
||||
|
||||
await action.perform()
|
||||
@@ -87,19 +86,18 @@ describe("Action", () => {
|
||||
generateReleaseNotes,
|
||||
makeLatest,
|
||||
createName,
|
||||
createPrerelease)
|
||||
createPrerelease
|
||||
)
|
||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('creates release if no draft releases', async () => {
|
||||
it("creates release if no draft releases", async () => {
|
||||
const action = createAction(true, true)
|
||||
const error = {status: 404}
|
||||
const error = { status: 404 }
|
||||
getMock.mockRejectedValue(error)
|
||||
listMock.mockResolvedValue({
|
||||
data: [
|
||||
{id: id, draft: false, tag_name: tag}
|
||||
]
|
||||
data: [{ id: id, draft: false, tag_name: tag }],
|
||||
})
|
||||
|
||||
await action.perform()
|
||||
@@ -117,10 +115,9 @@ describe("Action", () => {
|
||||
)
|
||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||
assertOutputApplied()
|
||||
|
||||
})
|
||||
|
||||
it('creates release then uploads artifact', async () => {
|
||||
it("creates release then uploads artifact", async () => {
|
||||
const action = createAction(false, true)
|
||||
|
||||
await action.perform()
|
||||
@@ -140,7 +137,7 @@ describe("Action", () => {
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('removes all artifacts when artifact destroyer is enabled', async () => {
|
||||
it("removes all artifacts when artifact destroyer is enabled", async () => {
|
||||
const action = createAction(false, true, true)
|
||||
|
||||
await action.perform()
|
||||
@@ -149,7 +146,7 @@ describe("Action", () => {
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('removes no artifacts when artifact destroyer is disabled', async () => {
|
||||
it("removes no artifacts when artifact destroyer is disabled", async () => {
|
||||
const action = createAction(false, true)
|
||||
|
||||
await action.perform()
|
||||
@@ -158,7 +155,7 @@ describe("Action", () => {
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('skips action', async () => {
|
||||
it("skips action", async () => {
|
||||
const action = createAction(false, false, false)
|
||||
shouldSkipMock.mockResolvedValue(true)
|
||||
|
||||
@@ -168,7 +165,7 @@ describe("Action", () => {
|
||||
expect(updateMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('throws error when create fails', async () => {
|
||||
it("throws error when create fails", async () => {
|
||||
const action = createAction(false, true)
|
||||
createMock.mockRejectedValue("error")
|
||||
|
||||
@@ -193,14 +190,14 @@ describe("Action", () => {
|
||||
expect(uploadMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('throws error when get fails', async () => {
|
||||
it("throws error when get fails", async () => {
|
||||
const action = createAction(true, true)
|
||||
const error = {
|
||||
errors: [
|
||||
{
|
||||
code: 'already_exists'
|
||||
}
|
||||
]
|
||||
code: "already_exists",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
createMock.mockRejectedValue(error)
|
||||
@@ -215,19 +212,17 @@ describe("Action", () => {
|
||||
expect(getMock).toBeCalledWith(tag)
|
||||
expect(updateMock).not.toBeCalled()
|
||||
expect(uploadMock).not.toBeCalled()
|
||||
|
||||
})
|
||||
|
||||
it('throws error when list has no data', async () => {
|
||||
|
||||
it("throws error when list has no data", async () => {
|
||||
const action = createAction(true, true)
|
||||
getMock.mockRejectedValue({status: 404})
|
||||
getMock.mockRejectedValue({ status: 404 })
|
||||
const error = {
|
||||
errors: [
|
||||
{
|
||||
code: 'already_exists'
|
||||
}
|
||||
]
|
||||
code: "already_exists",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
createMock.mockRejectedValue(error)
|
||||
@@ -244,7 +239,7 @@ describe("Action", () => {
|
||||
expect(updateMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('throws error when update fails', async () => {
|
||||
it("throws error when update fails", async () => {
|
||||
const action = createAction(true, true)
|
||||
|
||||
updateMock.mockRejectedValue("error")
|
||||
@@ -270,9 +265,9 @@ describe("Action", () => {
|
||||
expect(uploadMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('throws error when upload fails', async () => {
|
||||
it("throws error when upload fails", async () => {
|
||||
const action = createAction(false, true)
|
||||
const expectedError = {status: 404}
|
||||
const expectedError = { status: 404 }
|
||||
uploadMock.mockRejectedValue(expectedError)
|
||||
|
||||
expect.hasAssertions()
|
||||
@@ -296,15 +291,15 @@ describe("Action", () => {
|
||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||
})
|
||||
|
||||
it('updates draft release', async () => {
|
||||
it("updates draft release", async () => {
|
||||
const action = createAction(true, true)
|
||||
const error = {status: 404}
|
||||
const error = { status: 404 }
|
||||
getMock.mockRejectedValue(error)
|
||||
listMock.mockResolvedValue({
|
||||
data: [
|
||||
{id: 123, draft: false, tag_name: tag},
|
||||
{id: id, draft: true, tag_name: tag}
|
||||
]
|
||||
{ id: 123, draft: false, tag_name: tag },
|
||||
{ id: id, draft: true, tag_name: tag },
|
||||
],
|
||||
})
|
||||
|
||||
await action.perform()
|
||||
@@ -324,7 +319,7 @@ describe("Action", () => {
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('updates release but does not upload if no artifact', async () => {
|
||||
it("updates release but does not upload if no artifact", async () => {
|
||||
const action = createAction(true, false)
|
||||
|
||||
await action.perform()
|
||||
@@ -344,7 +339,7 @@ describe("Action", () => {
|
||||
assertOutputApplied()
|
||||
})
|
||||
|
||||
it('updates release then uploads artifact', async () => {
|
||||
it("updates release then uploads artifact", async () => {
|
||||
const action = createAction(true, true)
|
||||
|
||||
await action.perform()
|
||||
@@ -365,12 +360,10 @@ describe("Action", () => {
|
||||
})
|
||||
|
||||
function assertOutputApplied() {
|
||||
expect(applyReleaseDataMock).toBeCalledWith({id: releaseId, upload_url: url})
|
||||
expect(applyReleaseDataMock).toBeCalledWith({ id: releaseId, upload_url: url })
|
||||
}
|
||||
|
||||
function createAction(allowUpdates: boolean,
|
||||
hasArtifact: boolean,
|
||||
removeArtifacts: boolean = false): Action {
|
||||
function createAction(allowUpdates: boolean, hasArtifact: boolean, removeArtifacts: boolean = false): Action {
|
||||
let inputArtifact: Artifact[]
|
||||
if (hasArtifact) {
|
||||
inputArtifact = artifacts
|
||||
@@ -385,30 +378,30 @@ describe("Action", () => {
|
||||
listArtifactsForRelease: listArtifactsMock,
|
||||
listReleases: listMock,
|
||||
update: updateMock,
|
||||
uploadArtifact: jest.fn()
|
||||
uploadArtifact: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
createMock.mockResolvedValue({
|
||||
data: {
|
||||
id: releaseId,
|
||||
upload_url: url
|
||||
}
|
||||
upload_url: url,
|
||||
},
|
||||
})
|
||||
getMock.mockResolvedValue({
|
||||
data: {
|
||||
id: id
|
||||
}
|
||||
id: id,
|
||||
},
|
||||
})
|
||||
listMock.mockResolvedValue({
|
||||
data: []
|
||||
data: [],
|
||||
})
|
||||
shouldSkipMock.mockResolvedValue(false)
|
||||
updateMock.mockResolvedValue({
|
||||
data: {
|
||||
id: releaseId,
|
||||
upload_url: url
|
||||
}
|
||||
upload_url: url,
|
||||
},
|
||||
})
|
||||
uploadMock.mockResolvedValue({})
|
||||
|
||||
@@ -436,28 +429,28 @@ describe("Action", () => {
|
||||
updatedReleaseBody: updateBody,
|
||||
updatedReleaseName: updateName,
|
||||
updatedPrerelease: updatePrerelease,
|
||||
updateOnlyUnreleased: updateOnlyUnreleased
|
||||
updateOnlyUnreleased: updateOnlyUnreleased,
|
||||
}
|
||||
})
|
||||
const MockOutputs = jest.fn<Outputs, any>(() => {
|
||||
return {
|
||||
applyReleaseData: applyReleaseDataMock
|
||||
applyReleaseData: applyReleaseDataMock,
|
||||
}
|
||||
})
|
||||
const MockUploader = jest.fn<ArtifactUploader, any>(() => {
|
||||
return {
|
||||
uploadArtifacts: uploadMock
|
||||
uploadArtifacts: uploadMock,
|
||||
}
|
||||
})
|
||||
const MockArtifactDestroyer = jest.fn<ArtifactDestroyer, any>(() => {
|
||||
return {
|
||||
destroyArtifacts: artifactDestroyMock
|
||||
destroyArtifacts: artifactDestroyMock,
|
||||
}
|
||||
})
|
||||
|
||||
const MockActionSkipper = jest.fn<ActionSkipper, any>(() => {
|
||||
return {
|
||||
shouldSkip: shouldSkipMock
|
||||
shouldSkip: shouldSkipMock,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ActionSkipper, ReleaseActionSkipper} from "../src/ActionSkipper";
|
||||
import {Releases} from "../src/Releases";
|
||||
import { ActionSkipper, ReleaseActionSkipper } from "../src/ActionSkipper"
|
||||
import { Releases } from "../src/Releases"
|
||||
|
||||
describe("shouldSkip", () => {
|
||||
const getMock = jest.fn()
|
||||
@@ -12,31 +12,31 @@ describe("shouldSkip", () => {
|
||||
listArtifactsForRelease: jest.fn(),
|
||||
listReleases: jest.fn(),
|
||||
update: jest.fn(),
|
||||
uploadArtifact: jest.fn()
|
||||
uploadArtifact: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
it('should return false when skipIfReleaseExists is false', async () => {
|
||||
it("should return false when skipIfReleaseExists is false", async () => {
|
||||
const actionSkipper = new ReleaseActionSkipper(false, MockReleases(), tag)
|
||||
expect(await actionSkipper.shouldSkip()).toBe(false)
|
||||
})
|
||||
|
||||
it('should return false when error occurs', async () => {
|
||||
it("should return false when error occurs", async () => {
|
||||
getMock.mockRejectedValue(new Error())
|
||||
|
||||
const actionSkipper = new ReleaseActionSkipper(true, MockReleases(), tag)
|
||||
expect(await actionSkipper.shouldSkip()).toBe(false)
|
||||
})
|
||||
|
||||
it('should return false when release does not exist', async () => {
|
||||
it("should return false when release does not exist", async () => {
|
||||
getMock.mockResolvedValue({})
|
||||
|
||||
const actionSkipper = new ReleaseActionSkipper(true, MockReleases(), tag)
|
||||
expect(await actionSkipper.shouldSkip()).toBe(false)
|
||||
})
|
||||
|
||||
it('should return true when release does exist', async () => {
|
||||
getMock.mockResolvedValue({data: {}})
|
||||
it("should return true when release does exist", async () => {
|
||||
getMock.mockResolvedValue({ data: {} })
|
||||
|
||||
const actionSkipper = new ReleaseActionSkipper(true, MockReleases(), tag)
|
||||
expect(await actionSkipper.shouldSkip()).toBe(true)
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import {Artifact} from "../src/Artifact";
|
||||
import { Artifact } from "../src/Artifact"
|
||||
|
||||
const contentLength = 42
|
||||
const fakeReadStream = {}
|
||||
|
||||
jest.mock('fs', () => {
|
||||
jest.mock("fs", () => {
|
||||
return {
|
||||
createReadStream: () => fakeReadStream,
|
||||
statSync: () => {
|
||||
return {size: contentLength}
|
||||
}
|
||||
};
|
||||
return { size: contentLength }
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe("Artifact", () => {
|
||||
it('defaults contentType to raw', () => {
|
||||
const artifact = new Artifact('')
|
||||
expect(artifact.contentType).toBe('raw')
|
||||
it("defaults contentType to raw", () => {
|
||||
const artifact = new Artifact("")
|
||||
expect(artifact.contentType).toBe("raw")
|
||||
})
|
||||
|
||||
it('generates name from path', () => {
|
||||
const artifact = new Artifact('some/artifact')
|
||||
expect(artifact.name).toBe('artifact')
|
||||
it("generates name from path", () => {
|
||||
const artifact = new Artifact("some/artifact")
|
||||
expect(artifact.name).toBe("artifact")
|
||||
})
|
||||
|
||||
it('provides contentLength', () => {
|
||||
const artifact = new Artifact('some/artifact')
|
||||
it("provides contentLength", () => {
|
||||
const artifact = new Artifact("some/artifact")
|
||||
expect(artifact.contentLength).toBe(contentLength)
|
||||
})
|
||||
|
||||
it('provides path', () => {
|
||||
const artifact = new Artifact('some/artifact')
|
||||
expect(artifact.path).toBe('some/artifact')
|
||||
it("provides path", () => {
|
||||
const artifact = new Artifact("some/artifact")
|
||||
expect(artifact.path).toBe("some/artifact")
|
||||
})
|
||||
|
||||
it('reads artifact', () => {
|
||||
const artifact = new Artifact('some/artifact')
|
||||
it("reads artifact", () => {
|
||||
const artifact = new Artifact("some/artifact")
|
||||
expect(artifact.readFile()).toBe(fakeReadStream)
|
||||
})
|
||||
})
|
||||
@@ -1,22 +1,21 @@
|
||||
import {Artifact} from "../src/Artifact"
|
||||
import {GithubArtifactUploader} from "../src/ArtifactUploader"
|
||||
import {Releases} from "../src/Releases";
|
||||
import {RequestError} from '@octokit/request-error'
|
||||
import {GithubArtifactDestroyer} from "../src/ArtifactDestroyer";
|
||||
import { Artifact } from "../src/Artifact"
|
||||
import { GithubArtifactUploader } from "../src/ArtifactUploader"
|
||||
import { Releases } from "../src/Releases"
|
||||
import { RequestError } from "@octokit/request-error"
|
||||
import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer"
|
||||
|
||||
const releaseId = 100
|
||||
|
||||
const deleteMock = jest.fn()
|
||||
const listArtifactsMock = jest.fn()
|
||||
|
||||
|
||||
describe('ArtifactDestroyer', () => {
|
||||
describe("ArtifactDestroyer", () => {
|
||||
beforeEach(() => {
|
||||
deleteMock.mockClear()
|
||||
listArtifactsMock.mockClear()
|
||||
})
|
||||
|
||||
it('destroys all artifacts', async () => {
|
||||
it("destroys all artifacts", async () => {
|
||||
mockListWithAssets()
|
||||
mockDeleteSuccess()
|
||||
const destroyer = createDestroyer()
|
||||
@@ -26,7 +25,7 @@ describe('ArtifactDestroyer', () => {
|
||||
expect(deleteMock).toBeCalledTimes(2)
|
||||
})
|
||||
|
||||
it('destroys nothing when no artifacts found', async () => {
|
||||
it("destroys nothing when no artifacts found", async () => {
|
||||
mockListWithoutAssets()
|
||||
const destroyer = createDestroyer()
|
||||
|
||||
@@ -35,7 +34,7 @@ describe('ArtifactDestroyer', () => {
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('throws when delete call fails', async () => {
|
||||
it("throws when delete call fails", async () => {
|
||||
mockListWithAssets()
|
||||
mockDeleteError()
|
||||
const destroyer = createDestroyer()
|
||||
@@ -57,7 +56,7 @@ describe('ArtifactDestroyer', () => {
|
||||
listArtifactsForRelease: listArtifactsMock,
|
||||
listReleases: jest.fn(),
|
||||
update: jest.fn(),
|
||||
uploadArtifact: jest.fn()
|
||||
uploadArtifact: jest.fn(),
|
||||
}
|
||||
})
|
||||
return new GithubArtifactDestroyer(new MockReleases())
|
||||
@@ -75,16 +74,16 @@ describe('ArtifactDestroyer', () => {
|
||||
listArtifactsMock.mockResolvedValue([
|
||||
{
|
||||
name: "art1",
|
||||
id: 1
|
||||
id: 1,
|
||||
},
|
||||
{
|
||||
name: "art2",
|
||||
id: 2
|
||||
}
|
||||
id: 2,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
function mockListWithoutAssets() {
|
||||
listArtifactsMock.mockResolvedValue([])
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
const warnMock = jest.fn()
|
||||
|
||||
import {FileArtifactGlobber} from "../src/ArtifactGlobber"
|
||||
import {Globber} from "../src/Globber";
|
||||
import {Artifact} from "../src/Artifact";
|
||||
import untildify = require("untildify");
|
||||
import { FileArtifactGlobber } from "../src/ArtifactGlobber"
|
||||
import { Globber } from "../src/Globber"
|
||||
import { Artifact } from "../src/Artifact"
|
||||
import untildify = require("untildify")
|
||||
|
||||
const contentType = "raw"
|
||||
const globMock = jest.fn()
|
||||
const globResults = ["file1", "file2"]
|
||||
|
||||
jest.mock('@actions/core', () => {
|
||||
return {warning: warnMock};
|
||||
jest.mock("@actions/core", () => {
|
||||
return { warning: warnMock }
|
||||
})
|
||||
|
||||
jest.mock('fs', () => {
|
||||
jest.mock("fs", () => {
|
||||
return {
|
||||
statSync: () => {
|
||||
return {
|
||||
isDirectory(): boolean {
|
||||
return false
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
realpathSync: () => {
|
||||
return false
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe("ArtifactGlobber", () => {
|
||||
@@ -36,76 +36,63 @@ describe("ArtifactGlobber", () => {
|
||||
it("expands paths in which start with a ~", () => {
|
||||
const globber = createArtifactGlobber()
|
||||
|
||||
const expectedArtifacts =
|
||||
globResults.map((path) => new Artifact(path, contentType))
|
||||
const expectedArtifacts = globResults.map((path) => new Artifact(path, contentType))
|
||||
|
||||
expect(globber.globArtifactString('~/path', 'raw', false))
|
||||
.toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith(untildify('~/path'))
|
||||
expect(globber.globArtifactString("~/path", "raw", false)).toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith(untildify("~/path"))
|
||||
expect(warnMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("globs simple path", () => {
|
||||
const globber = createArtifactGlobber()
|
||||
|
||||
const expectedArtifacts =
|
||||
globResults.map((path) => new Artifact(path, contentType))
|
||||
const expectedArtifacts = globResults.map((path) => new Artifact(path, contentType))
|
||||
|
||||
expect(globber.globArtifactString('path', 'raw', false))
|
||||
.toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith('path')
|
||||
expect(globber.globArtifactString("path", "raw", false)).toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith("path")
|
||||
expect(warnMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("splits multiple paths with comma separator", () => {
|
||||
const globber = createArtifactGlobber()
|
||||
|
||||
const expectedArtifacts =
|
||||
globResults
|
||||
.concat(globResults)
|
||||
.map((path) => new Artifact(path, contentType))
|
||||
const expectedArtifacts = globResults.concat(globResults).map((path) => new Artifact(path, contentType))
|
||||
|
||||
expect(globber.globArtifactString('path1,path2', 'raw', false))
|
||||
.toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith('path1')
|
||||
expect(globMock).toBeCalledWith('path2')
|
||||
expect(globber.globArtifactString("path1,path2", "raw", false)).toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith("path1")
|
||||
expect(globMock).toBeCalledWith("path2")
|
||||
expect(warnMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("splits multiple paths with new line separator and trims start", () => {
|
||||
const globber = createArtifactGlobber()
|
||||
|
||||
const expectedArtifacts =
|
||||
globResults
|
||||
.concat(globResults)
|
||||
.map((path) => new Artifact(path, contentType))
|
||||
const expectedArtifacts = globResults.concat(globResults).map((path) => new Artifact(path, contentType))
|
||||
|
||||
expect(globber.globArtifactString('path1\n path2', 'raw', false))
|
||||
.toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith('path1')
|
||||
expect(globMock).toBeCalledWith('path2')
|
||||
expect(globber.globArtifactString("path1\n path2", "raw", false)).toEqual(expectedArtifacts)
|
||||
expect(globMock).toBeCalledWith("path1")
|
||||
expect(globMock).toBeCalledWith("path2")
|
||||
expect(warnMock).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("warns when no glob results are produced and empty results shouldn't throw", () => {
|
||||
const globber = createArtifactGlobber([])
|
||||
|
||||
expect(globber.globArtifactString('path', 'raw', false))
|
||||
.toEqual([])
|
||||
expect(globber.globArtifactString("path", "raw", false)).toEqual([])
|
||||
expect(warnMock).toBeCalled()
|
||||
})
|
||||
|
||||
it("throws when no glob results are produced and empty results shouild throw", () => {
|
||||
const globber = createArtifactGlobber([])
|
||||
expect(() => {
|
||||
globber.globArtifactString('path', 'raw', true)
|
||||
globber.globArtifactString("path", "raw", true)
|
||||
}).toThrow()
|
||||
})
|
||||
|
||||
function createArtifactGlobber(results: string[] = globResults): FileArtifactGlobber {
|
||||
const MockGlobber = jest.fn<Globber, any>(() => {
|
||||
return {
|
||||
glob: globMock
|
||||
glob: globMock,
|
||||
}
|
||||
})
|
||||
globMock.mockReturnValue(results)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
const directoryMock = jest.fn()
|
||||
const warnMock = jest.fn()
|
||||
|
||||
import {ArtifactPathValidator} from "../src/ArtifactPathValidator";
|
||||
import { ArtifactPathValidator } from "../src/ArtifactPathValidator"
|
||||
|
||||
const pattern = 'pattern'
|
||||
const pattern = "pattern"
|
||||
|
||||
jest.mock('@actions/core', () => {
|
||||
return {warning: warnMock};
|
||||
jest.mock("@actions/core", () => {
|
||||
return { warning: warnMock }
|
||||
})
|
||||
|
||||
jest.mock('fs', () => {
|
||||
jest.mock("fs", () => {
|
||||
return {
|
||||
statSync: () => {
|
||||
return {isDirectory: directoryMock}
|
||||
}
|
||||
};
|
||||
return { isDirectory: directoryMock }
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe("ArtifactPathValidator", () => {
|
||||
@@ -24,14 +24,14 @@ describe("ArtifactPathValidator", () => {
|
||||
})
|
||||
|
||||
it("warns and filters out path which points to a directory", () => {
|
||||
const paths = ['path1', 'path2']
|
||||
const paths = ["path1", "path2"]
|
||||
directoryMock.mockReturnValueOnce(true).mockReturnValueOnce(false)
|
||||
|
||||
const validator = new ArtifactPathValidator(false, paths, pattern)
|
||||
|
||||
const result = validator.validate()
|
||||
expect(warnMock).toBeCalled()
|
||||
expect(result).toEqual(['path2'])
|
||||
expect(result).toEqual(["path2"])
|
||||
})
|
||||
|
||||
it("warns when no glob results are produced and empty results shouldn't throw", () => {
|
||||
@@ -48,7 +48,7 @@ describe("ArtifactPathValidator", () => {
|
||||
})
|
||||
|
||||
it("throws when path points to directory", () => {
|
||||
const paths = ['path1', 'path2']
|
||||
const paths = ["path1", "path2"]
|
||||
directoryMock.mockReturnValueOnce(true).mockReturnValueOnce(false)
|
||||
|
||||
const validator = new ArtifactPathValidator(true, paths, pattern)
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
import {Artifact} from "../src/Artifact"
|
||||
import {GithubArtifactUploader} from "../src/ArtifactUploader"
|
||||
import {Releases} from "../src/Releases";
|
||||
import {RequestError} from '@octokit/request-error'
|
||||
import { Artifact } from "../src/Artifact"
|
||||
import { GithubArtifactUploader } from "../src/ArtifactUploader"
|
||||
import { Releases } from "../src/Releases"
|
||||
import { RequestError } from "@octokit/request-error"
|
||||
|
||||
const artifacts = [
|
||||
new Artifact('a/art1'),
|
||||
new Artifact('b/art2')
|
||||
]
|
||||
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
|
||||
const fakeReadStream = {}
|
||||
const contentLength = 42
|
||||
const releaseId = 100
|
||||
const url = 'http://api.example.com'
|
||||
const url = "http://api.example.com"
|
||||
|
||||
const deleteMock = jest.fn()
|
||||
const listArtifactsMock = jest.fn()
|
||||
const uploadMock = jest.fn()
|
||||
|
||||
jest.mock('fs', () => {
|
||||
const originalFs = jest.requireActual('fs');
|
||||
jest.mock("fs", () => {
|
||||
const originalFs = jest.requireActual("fs")
|
||||
return {
|
||||
...originalFs,
|
||||
promises: {},
|
||||
createReadStream: () => fakeReadStream,
|
||||
statSync: () => {
|
||||
return {size: contentLength};
|
||||
}
|
||||
};
|
||||
});
|
||||
return { size: contentLength }
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe('ArtifactUploader', () => {
|
||||
describe("ArtifactUploader", () => {
|
||||
beforeEach(() => {
|
||||
deleteMock.mockClear()
|
||||
listArtifactsMock.mockClear()
|
||||
uploadMock.mockClear()
|
||||
})
|
||||
|
||||
it('abort when upload failed with non-5xx response', async () => {
|
||||
it("abort when upload failed with non-5xx response", async () => {
|
||||
mockListWithoutAssets()
|
||||
mockUploadArtifact(401, 2)
|
||||
const uploader = createUploader(true)
|
||||
@@ -43,15 +40,13 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(2)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('abort when upload failed with 5xx response after 3 attempts', async () => {
|
||||
it("abort when upload failed with 5xx response after 3 attempts", async () => {
|
||||
mockListWithoutAssets()
|
||||
mockUploadArtifact(500, 4)
|
||||
const uploader = createUploader(true)
|
||||
@@ -59,21 +54,16 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(5)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('replaces all artifacts', async () => {
|
||||
it("replaces all artifacts", async () => {
|
||||
mockDeleteSuccess()
|
||||
mockListWithAssets()
|
||||
mockUploadArtifact()
|
||||
@@ -82,17 +72,15 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(2)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(2)
|
||||
expect(deleteMock).toBeCalledWith(1)
|
||||
expect(deleteMock).toBeCalledWith(2)
|
||||
})
|
||||
|
||||
it('replaces no artifacts when previous asset list empty', async () => {
|
||||
it("replaces no artifacts when previous asset list empty", async () => {
|
||||
mockDeleteSuccess()
|
||||
mockListWithoutAssets()
|
||||
mockUploadArtifact()
|
||||
@@ -101,15 +89,13 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(2)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('retry when upload failed with 5xx response', async () => {
|
||||
it("retry when upload failed with 5xx response", async () => {
|
||||
mockListWithoutAssets()
|
||||
mockUploadArtifact(500, 2)
|
||||
const uploader = createUploader(true)
|
||||
@@ -117,19 +103,15 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(4)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('throws upload error when replacesExistingArtifacts is true', async () => {
|
||||
it("throws upload error when replacesExistingArtifacts is true", async () => {
|
||||
mockListWithoutAssets()
|
||||
mockUploadError()
|
||||
const uploader = createUploader(true, true)
|
||||
@@ -142,7 +124,7 @@ describe('ArtifactUploader', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('throws error from replace', async () => {
|
||||
it("throws error from replace", async () => {
|
||||
mockDeleteError()
|
||||
mockListWithAssets()
|
||||
mockUploadArtifact()
|
||||
@@ -156,7 +138,7 @@ describe('ArtifactUploader', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('updates all artifacts, delete none', async () => {
|
||||
it("updates all artifacts, delete none", async () => {
|
||||
mockDeleteError()
|
||||
mockListWithAssets()
|
||||
mockUploadArtifact()
|
||||
@@ -165,10 +147,8 @@ describe('ArtifactUploader', () => {
|
||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
||||
|
||||
expect(uploadMock).toBeCalledTimes(2)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art1', releaseId)
|
||||
expect(uploadMock)
|
||||
.toBeCalledWith(url, contentLength, 'raw', fakeReadStream, 'art2', releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
|
||||
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
|
||||
|
||||
expect(deleteMock).toBeCalledTimes(0)
|
||||
})
|
||||
@@ -182,7 +162,7 @@ describe('ArtifactUploader', () => {
|
||||
listArtifactsForRelease: listArtifactsMock,
|
||||
listReleases: jest.fn(),
|
||||
update: jest.fn(),
|
||||
uploadArtifact: uploadMock
|
||||
uploadArtifact: uploadMock,
|
||||
}
|
||||
})
|
||||
return new GithubArtifactUploader(new MockReleases(), replaces, throws)
|
||||
@@ -200,12 +180,12 @@ describe('ArtifactUploader', () => {
|
||||
listArtifactsMock.mockResolvedValue([
|
||||
{
|
||||
name: "art1",
|
||||
id: 1
|
||||
id: 1,
|
||||
},
|
||||
{
|
||||
name: "art2",
|
||||
id: 2
|
||||
}
|
||||
id: 2,
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
@@ -216,7 +196,7 @@ describe('ArtifactUploader', () => {
|
||||
function mockUploadArtifact(status: number = 200, failures: number = 0) {
|
||||
const error = new RequestError(`HTTP ${status}`, status, {
|
||||
headers: {},
|
||||
request: {method: 'GET', url: '', headers: {}}
|
||||
request: { method: "GET", url: "", headers: {} },
|
||||
})
|
||||
for (let index = 0; index < failures; index++) {
|
||||
uploadMock.mockRejectedValueOnce(error)
|
||||
@@ -227,7 +207,7 @@ describe('ArtifactUploader', () => {
|
||||
function mockUploadError() {
|
||||
uploadMock.mockRejectedValue({
|
||||
message: "error",
|
||||
status: 502
|
||||
status: 502,
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,93 +1,95 @@
|
||||
import { GithubError } from "../src/GithubError"
|
||||
|
||||
describe('ErrorMessage', () => {
|
||||
|
||||
describe('has error with code', () => {
|
||||
describe("ErrorMessage", () => {
|
||||
describe("has error with code", () => {
|
||||
const error = {
|
||||
message: 'something bad happened',
|
||||
message: "something bad happened",
|
||||
errors: [
|
||||
{
|
||||
code: 'missing',
|
||||
resource: 'release'
|
||||
code: "missing",
|
||||
resource: "release",
|
||||
},
|
||||
{
|
||||
code: 'already_exists',
|
||||
resource: 'release'
|
||||
}
|
||||
code: "already_exists",
|
||||
resource: "release",
|
||||
},
|
||||
],
|
||||
status: 422
|
||||
status: 422,
|
||||
}
|
||||
|
||||
it('does not have error', () => {
|
||||
it("does not have error", () => {
|
||||
const githubError = new GithubError(error)
|
||||
expect(githubError.hasErrorWithCode('missing_field')).toBeFalsy()
|
||||
expect(githubError.hasErrorWithCode("missing_field")).toBeFalsy()
|
||||
})
|
||||
|
||||
it('has error', () => {
|
||||
it("has error", () => {
|
||||
const githubError = new GithubError(error)
|
||||
expect(githubError.hasErrorWithCode('missing')).toBeTruthy()
|
||||
expect(githubError.hasErrorWithCode("missing")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('has error with remediation', () => {
|
||||
it('provides remediation with 404 without errors', () => {
|
||||
describe("has error with remediation", () => {
|
||||
it("provides remediation with 404 without errors", () => {
|
||||
const error = { status: 404, message: "message" }
|
||||
const githubError = new GithubError(error)
|
||||
expect(githubError.toString())
|
||||
.toBe('Error 404: message\nMake sure your github token has access to the repo and has permission to author releases')
|
||||
expect(githubError.toString()).toBe(
|
||||
"Error 404: message\nMake sure your github token has access to the repo and has permission to author releases"
|
||||
)
|
||||
})
|
||||
|
||||
it('provides remediation with 404 with errors', () => {
|
||||
it("provides remediation with 404 with errors", () => {
|
||||
const error = {
|
||||
message: 'message',
|
||||
message: "message",
|
||||
errors: [
|
||||
{
|
||||
code: 'missing',
|
||||
resource: 'release'
|
||||
}
|
||||
code: "missing",
|
||||
resource: "release",
|
||||
},
|
||||
],
|
||||
status: 404
|
||||
status: 404,
|
||||
}
|
||||
const githubError = new GithubError(error)
|
||||
expect(githubError.toString())
|
||||
.toBe('Error 404: message\nErrors:\n- release does not exist.\nMake sure your github token has access to the repo and has permission to author releases')
|
||||
expect(githubError.toString()).toBe(
|
||||
"Error 404: message\nErrors:\n- release does not exist.\nMake sure your github token has access to the repo and has permission to author releases"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('generates message with errors', () => {
|
||||
it("generates message with errors", () => {
|
||||
const error = {
|
||||
message: 'something bad happened',
|
||||
message: "something bad happened",
|
||||
errors: [
|
||||
{
|
||||
code: 'missing',
|
||||
resource: 'release'
|
||||
code: "missing",
|
||||
resource: "release",
|
||||
},
|
||||
{
|
||||
code: 'already_exists',
|
||||
resource: 'release'
|
||||
}
|
||||
code: "already_exists",
|
||||
resource: "release",
|
||||
},
|
||||
],
|
||||
status: 422
|
||||
status: 422,
|
||||
}
|
||||
|
||||
const githubError = new GithubError(error)
|
||||
|
||||
const expectedString = "Error 422: something bad happened\nErrors:\n- release does not exist.\n- release already exists."
|
||||
const expectedString =
|
||||
"Error 422: something bad happened\nErrors:\n- release does not exist.\n- release already exists."
|
||||
expect(githubError.toString()).toBe(expectedString)
|
||||
})
|
||||
|
||||
it('generates message without errors', () => {
|
||||
it("generates message without errors", () => {
|
||||
const error = {
|
||||
message: 'something bad happened',
|
||||
status: 422
|
||||
message: "something bad happened",
|
||||
status: 422,
|
||||
}
|
||||
|
||||
const githubError = new GithubError(error)
|
||||
|
||||
expect(githubError.toString()).toBe('Error 422: something bad happened')
|
||||
expect(githubError.toString()).toBe("Error 422: something bad happened")
|
||||
})
|
||||
|
||||
it('provides error status', () => {
|
||||
it("provides error status", () => {
|
||||
const error = { status: 404 }
|
||||
const githubError = new GithubError(error)
|
||||
expect(githubError.status).toBe(404)
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
import { GithubErrorDetail } from "../src/GithubErrorDetail"
|
||||
|
||||
describe('GithubErrorDetail', () => {
|
||||
|
||||
it('provides error code', () => {
|
||||
describe("GithubErrorDetail", () => {
|
||||
it("provides error code", () => {
|
||||
const error = {
|
||||
code: "missing"
|
||||
code: "missing",
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
|
||||
expect(detail.code).toBe('missing')
|
||||
expect(detail.code).toBe("missing")
|
||||
})
|
||||
|
||||
it('generates missing resource error message', () => {
|
||||
it("generates missing resource error message", () => {
|
||||
const resource = "release"
|
||||
const error = {
|
||||
code: "missing",
|
||||
resource: resource
|
||||
resource: resource,
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
@@ -25,13 +24,13 @@ describe('GithubErrorDetail', () => {
|
||||
expect(message).toBe(`${resource} does not exist.`)
|
||||
})
|
||||
|
||||
it('generates missing field error message', () => {
|
||||
it("generates missing field error message", () => {
|
||||
const resource = "release"
|
||||
const field = "body"
|
||||
const error = {
|
||||
code: "missing_field",
|
||||
field: field,
|
||||
resource: resource
|
||||
resource: resource,
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
@@ -40,13 +39,13 @@ describe('GithubErrorDetail', () => {
|
||||
expect(message).toBe(`The ${field} field on ${resource} is missing.`)
|
||||
})
|
||||
|
||||
it('generates invalid field error message', () => {
|
||||
it("generates invalid field error message", () => {
|
||||
const resource = "release"
|
||||
const field = "body"
|
||||
const error = {
|
||||
code: "invalid",
|
||||
field: field,
|
||||
resource: resource
|
||||
resource: resource,
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
@@ -55,11 +54,11 @@ describe('GithubErrorDetail', () => {
|
||||
expect(message).toBe(`The ${field} field on ${resource} is an invalid format.`)
|
||||
})
|
||||
|
||||
it('generates resource already exists error message', () => {
|
||||
it("generates resource already exists error message", () => {
|
||||
const resource = "release"
|
||||
const error = {
|
||||
code: "already_exists",
|
||||
resource: resource
|
||||
resource: resource,
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
@@ -68,13 +67,13 @@ describe('GithubErrorDetail', () => {
|
||||
expect(message).toBe(`${resource} already exists.`)
|
||||
})
|
||||
|
||||
describe('generates custom error message', () => {
|
||||
it('with documentation url', () => {
|
||||
describe("generates custom error message", () => {
|
||||
it("with documentation url", () => {
|
||||
const url = "https://api.example.com"
|
||||
const error = {
|
||||
code: "custom",
|
||||
message: "foo",
|
||||
documentation_url: url
|
||||
documentation_url: url,
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
@@ -83,16 +82,16 @@ describe('GithubErrorDetail', () => {
|
||||
expect(message).toBe(`foo\nPlease see ${url}.`)
|
||||
})
|
||||
|
||||
it('without documentation url', () => {
|
||||
it("without documentation url", () => {
|
||||
const error = {
|
||||
code: "custom",
|
||||
message: "foo"
|
||||
message: "foo",
|
||||
}
|
||||
|
||||
const detail = new GithubErrorDetail(error)
|
||||
const message = detail.toString()
|
||||
|
||||
expect(message).toBe('foo')
|
||||
expect(message).toBe("foo")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,27 +1,24 @@
|
||||
const mockGetInput = jest.fn();
|
||||
const mockGetBooleanInput = jest.fn();
|
||||
const mockGetInput = jest.fn()
|
||||
const mockGetBooleanInput = jest.fn()
|
||||
const mockGlob = jest.fn()
|
||||
const mockReadFileSync = jest.fn();
|
||||
const mockStatSync = jest.fn();
|
||||
const mockReadFileSync = jest.fn()
|
||||
const mockStatSync = jest.fn()
|
||||
|
||||
import {Artifact} from "../src/Artifact";
|
||||
import {ArtifactGlobber} from "../src/ArtifactGlobber";
|
||||
import {Context} from "@actions/github/lib/context";
|
||||
import {Inputs, CoreInputs} from "../src/Inputs";
|
||||
import { Artifact } from "../src/Artifact"
|
||||
import { ArtifactGlobber } from "../src/ArtifactGlobber"
|
||||
import { Context } from "@actions/github/lib/context"
|
||||
import { Inputs, CoreInputs } from "../src/Inputs"
|
||||
|
||||
const artifacts = [
|
||||
new Artifact('a/art1'),
|
||||
new Artifact('b/art2')
|
||||
]
|
||||
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
|
||||
|
||||
jest.mock('@actions/core', () => {
|
||||
jest.mock("@actions/core", () => {
|
||||
return {
|
||||
getInput: mockGetInput,
|
||||
getBooleanInput: mockGetBooleanInput
|
||||
};
|
||||
getBooleanInput: mockGetBooleanInput,
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock('fs', () => {
|
||||
jest.mock("fs", () => {
|
||||
// existsSync is used by Context's constructor
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
return {
|
||||
@@ -29,452 +26,397 @@ jest.mock('fs', () => {
|
||||
return false
|
||||
},
|
||||
readFileSync: mockReadFileSync,
|
||||
statSync: mockStatSync
|
||||
};
|
||||
statSync: mockStatSync,
|
||||
}
|
||||
})
|
||||
|
||||
describe('Inputs', () => {
|
||||
let context: Context;
|
||||
let inputs: Inputs;
|
||||
describe("Inputs", () => {
|
||||
let context: Context
|
||||
let inputs: Inputs
|
||||
beforeEach(() => {
|
||||
mockGetInput.mockReset()
|
||||
context = new Context()
|
||||
inputs = new CoreInputs(createGlobber(), context)
|
||||
})
|
||||
|
||||
describe('commit', () => {
|
||||
it('returns commit', () => {
|
||||
mockGetInput.mockReturnValueOnce('commit')
|
||||
expect(inputs.commit).toBe('commit')
|
||||
describe("commit", () => {
|
||||
it("returns commit", () => {
|
||||
mockGetInput.mockReturnValueOnce("commit")
|
||||
expect(inputs.commit).toBe("commit")
|
||||
})
|
||||
|
||||
it('returns undefined when omitted', () => {
|
||||
mockGetInput.mockReturnValueOnce('')
|
||||
it("returns undefined when omitted", () => {
|
||||
mockGetInput.mockReturnValueOnce("")
|
||||
expect(inputs.commit).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
it('returns token', () => {
|
||||
mockGetInput.mockReturnValue('42')
|
||||
expect(inputs.token).toBe('42')
|
||||
it("returns token", () => {
|
||||
mockGetInput.mockReturnValue("42")
|
||||
expect(inputs.token).toBe("42")
|
||||
})
|
||||
|
||||
describe('allowsUpdates', () => {
|
||||
it('returns false', () => {
|
||||
describe("allowsUpdates", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.allowUpdates).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.allowUpdates).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('artifactErrorsFailBuild', () => {
|
||||
it('returns false', () => {
|
||||
describe("artifactErrorsFailBuild", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.artifactErrorsFailBuild).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.artifactErrorsFailBuild).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('artifacts', () => {
|
||||
it('globber told to throw errors', () => {
|
||||
mockGetInput.mockReturnValueOnce('art1')
|
||||
.mockReturnValueOnce('contentType')
|
||||
.mockReturnValueOnce('true')
|
||||
describe("artifacts", () => {
|
||||
it("globber told to throw errors", () => {
|
||||
mockGetInput.mockReturnValueOnce("art1").mockReturnValueOnce("contentType").mockReturnValueOnce("true")
|
||||
|
||||
expect(inputs.artifacts).toEqual(artifacts)
|
||||
expect(mockGlob).toBeCalledTimes(1)
|
||||
expect(mockGlob).toBeCalledWith('art1', 'contentType', true)
|
||||
expect(mockGlob).toBeCalledWith("art1", "contentType", true)
|
||||
})
|
||||
|
||||
it('returns empty artifacts', () => {
|
||||
mockGetInput.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('')
|
||||
it("returns empty artifacts", () => {
|
||||
mockGetInput.mockReturnValueOnce("").mockReturnValueOnce("")
|
||||
|
||||
expect(inputs.artifacts).toEqual([])
|
||||
expect(mockGlob).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('returns input.artifacts', () => {
|
||||
mockGetInput.mockReturnValueOnce('art1')
|
||||
.mockReturnValueOnce('contentType')
|
||||
.mockReturnValueOnce('false')
|
||||
it("returns input.artifacts", () => {
|
||||
mockGetInput.mockReturnValueOnce("art1").mockReturnValueOnce("contentType").mockReturnValueOnce("false")
|
||||
|
||||
expect(inputs.artifacts).toEqual(artifacts)
|
||||
expect(mockGlob).toBeCalledTimes(1)
|
||||
expect(mockGlob).toBeCalledWith('art1', 'contentType', false)
|
||||
expect(mockGlob).toBeCalledWith("art1", "contentType", false)
|
||||
})
|
||||
|
||||
it('returns input.artifacts with default contentType', () => {
|
||||
mockGetInput.mockReturnValueOnce('art1')
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('false')
|
||||
it("returns input.artifacts with default contentType", () => {
|
||||
mockGetInput.mockReturnValueOnce("art1").mockReturnValueOnce("").mockReturnValueOnce("false")
|
||||
|
||||
expect(inputs.artifacts).toEqual(artifacts)
|
||||
expect(mockGlob).toBeCalledTimes(1)
|
||||
expect(mockGlob).toBeCalledWith('art1', 'raw', false)
|
||||
expect(mockGlob).toBeCalledWith("art1", "raw", false)
|
||||
})
|
||||
|
||||
it('returns input.artifact', () => {
|
||||
mockGetInput.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('art2')
|
||||
.mockReturnValueOnce('contentType')
|
||||
.mockReturnValueOnce('false')
|
||||
it("returns input.artifact", () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce("")
|
||||
.mockReturnValueOnce("art2")
|
||||
.mockReturnValueOnce("contentType")
|
||||
.mockReturnValueOnce("false")
|
||||
|
||||
expect(inputs.artifacts).toEqual(artifacts)
|
||||
expect(mockGlob).toBeCalledTimes(1)
|
||||
expect(mockGlob).toBeCalledWith('art2', 'contentType', false)
|
||||
expect(mockGlob).toBeCalledWith("art2", "contentType", false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('createdDraft', () => {
|
||||
it('returns false', () => {
|
||||
describe("createdDraft", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.createdDraft).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.createdDraft).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('createdReleaseBody', () => {
|
||||
it('returns input body', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('body')
|
||||
expect(inputs.createdReleaseBody).toBe('body')
|
||||
describe("createdReleaseBody", () => {
|
||||
it("returns input body", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("body")
|
||||
expect(inputs.createdReleaseBody).toBe("body")
|
||||
})
|
||||
|
||||
it('returns body file contents', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('a/path')
|
||||
mockReadFileSync.mockReturnValue('file')
|
||||
it("returns body file contents", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("").mockReturnValueOnce("a/path")
|
||||
mockReadFileSync.mockReturnValue("file")
|
||||
|
||||
expect(inputs.createdReleaseBody).toBe('file')
|
||||
expect(inputs.createdReleaseBody).toBe("file")
|
||||
})
|
||||
|
||||
it('returns empty', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('')
|
||||
expect(inputs.createdReleaseBody).toBe('')
|
||||
it("returns empty", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("").mockReturnValueOnce("")
|
||||
expect(inputs.createdReleaseBody).toBe("")
|
||||
})
|
||||
|
||||
it('returns undefined when omitted', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('body')
|
||||
it("returns undefined when omitted", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("body")
|
||||
expect(inputs.createdReleaseBody).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('createdReleaseName', () => {
|
||||
it('returns input name', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('name')
|
||||
expect(inputs.createdReleaseName).toBe('name')
|
||||
describe("createdReleaseName", () => {
|
||||
it("returns input name", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("name")
|
||||
expect(inputs.createdReleaseName).toBe("name")
|
||||
})
|
||||
|
||||
it('returns undefined when omitted', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('name')
|
||||
it("returns undefined when omitted", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("name")
|
||||
expect(inputs.createdReleaseName).toBeUndefined()
|
||||
})
|
||||
|
||||
it('returns tag', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
context.ref = 'refs/tags/sha-tag'
|
||||
expect(inputs.createdReleaseName).toBe('sha-tag')
|
||||
it("returns tag", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("")
|
||||
context.ref = "refs/tags/sha-tag"
|
||||
expect(inputs.createdReleaseName).toBe("sha-tag")
|
||||
})
|
||||
})
|
||||
|
||||
describe('discussionCategory', () => {
|
||||
it('returns category', () => {
|
||||
mockGetInput.mockReturnValue('Release')
|
||||
expect(inputs.discussionCategory).toBe('Release')
|
||||
describe("discussionCategory", () => {
|
||||
it("returns category", () => {
|
||||
mockGetInput.mockReturnValue("Release")
|
||||
expect(inputs.discussionCategory).toBe("Release")
|
||||
})
|
||||
|
||||
it('returns undefined', () => {
|
||||
mockGetInput.mockReturnValue('')
|
||||
it("returns undefined", () => {
|
||||
mockGetInput.mockReturnValue("")
|
||||
expect(inputs.discussionCategory).toBe(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateReleaseNotes', () => {
|
||||
it('returns returns true', function () {
|
||||
describe("generateReleaseNotes", () => {
|
||||
it("returns returns true", function () {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.generateReleaseNotes).toBe(true)
|
||||
});
|
||||
})
|
||||
|
||||
it('returns false when omitted', function () {
|
||||
it("returns false when omitted", function () {
|
||||
mockGetInput.mockReturnValue("")
|
||||
expect(inputs.generateReleaseNotes).toBe(false)
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('makeLatest', () => {
|
||||
it('returns legacy', () => {
|
||||
mockGetInput.mockReturnValueOnce('legacy')
|
||||
expect(inputs.makeLatest).toBe('legacy')
|
||||
describe("makeLatest", () => {
|
||||
it("returns legacy", () => {
|
||||
mockGetInput.mockReturnValueOnce("legacy")
|
||||
expect(inputs.makeLatest).toBe("legacy")
|
||||
})
|
||||
|
||||
it('returns false', () => {
|
||||
mockGetInput.mockReturnValueOnce('false')
|
||||
expect(inputs.makeLatest).toBe('false')
|
||||
it("returns false", () => {
|
||||
mockGetInput.mockReturnValueOnce("false")
|
||||
expect(inputs.makeLatest).toBe("false")
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValueOnce('true')
|
||||
expect(inputs.makeLatest).toBe('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValueOnce("true")
|
||||
expect(inputs.makeLatest).toBe("true")
|
||||
})
|
||||
|
||||
it('returns undefined', () => {
|
||||
mockGetInput.mockReturnValueOnce('something_else')
|
||||
it("returns undefined", () => {
|
||||
mockGetInput.mockReturnValueOnce("something_else")
|
||||
expect(inputs.makeLatest).toBe(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('owner', () => {
|
||||
it('returns owner from context', function () {
|
||||
describe("owner", () => {
|
||||
it("returns owner from context", function () {
|
||||
process.env.GITHUB_REPOSITORY = "owner/repo"
|
||||
mockGetInput.mockReturnValue("")
|
||||
expect(inputs.owner).toBe("owner")
|
||||
});
|
||||
it('returns owner from inputs', function () {
|
||||
})
|
||||
it("returns owner from inputs", function () {
|
||||
mockGetInput.mockReturnValue("owner")
|
||||
expect(inputs.owner).toBe("owner")
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('createdPrerelase', () => {
|
||||
it('returns false', () => {
|
||||
describe("createdPrerelase", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.createdPrerelease).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.createdPrerelease).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('replacesArtifacts', () => {
|
||||
it('returns false', () => {
|
||||
describe("replacesArtifacts", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.replacesArtifacts).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.replacesArtifacts).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('removeArtifacts', () => {
|
||||
it('returns false', () => {
|
||||
describe("removeArtifacts", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.removeArtifacts).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValue("true")
|
||||
expect(inputs.removeArtifacts).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('repo', () => {
|
||||
it('returns repo from context', function () {
|
||||
describe("repo", () => {
|
||||
it("returns repo from context", function () {
|
||||
process.env.GITHUB_REPOSITORY = "owner/repo"
|
||||
mockGetInput.mockReturnValue("")
|
||||
expect(inputs.repo).toBe("repo")
|
||||
});
|
||||
it('returns repo from inputs', function () {
|
||||
})
|
||||
it("returns repo from inputs", function () {
|
||||
mockGetInput.mockReturnValue("repo")
|
||||
expect(inputs.repo).toBe("repo")
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('skipIfReleaseExists', () => {
|
||||
it('returns false', () => {
|
||||
describe("skipIfReleaseExists", () => {
|
||||
it("returns false", () => {
|
||||
mockGetBooleanInput.mockReturnValue(false)
|
||||
expect(inputs.skipIfReleaseExists).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
it("returns true", () => {
|
||||
mockGetBooleanInput.mockReturnValue(true)
|
||||
expect(inputs.skipIfReleaseExists).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('tag', () => {
|
||||
it('returns input tag', () => {
|
||||
mockGetInput.mockReturnValue('tag')
|
||||
expect(inputs.tag).toBe('tag')
|
||||
describe("tag", () => {
|
||||
it("returns input tag", () => {
|
||||
mockGetInput.mockReturnValue("tag")
|
||||
expect(inputs.tag).toBe("tag")
|
||||
})
|
||||
it('returns context sha when input is empty', () => {
|
||||
mockGetInput.mockReturnValue('')
|
||||
context.ref = 'refs/tags/sha-tag'
|
||||
expect(inputs.tag).toBe('sha-tag')
|
||||
it("returns context sha when input is empty", () => {
|
||||
mockGetInput.mockReturnValue("")
|
||||
context.ref = "refs/tags/sha-tag"
|
||||
expect(inputs.tag).toBe("sha-tag")
|
||||
})
|
||||
it('returns context sha when input is null', () => {
|
||||
it("returns context sha when input is null", () => {
|
||||
mockGetInput.mockReturnValue(null)
|
||||
context.ref = 'refs/tags/sha-tag'
|
||||
expect(inputs.tag).toBe('sha-tag')
|
||||
context.ref = "refs/tags/sha-tag"
|
||||
expect(inputs.tag).toBe("sha-tag")
|
||||
})
|
||||
it('throws if no tag', () => {
|
||||
it("throws if no tag", () => {
|
||||
context.ref = ""
|
||||
expect(() => inputs.tag).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updatedDraft', () => {
|
||||
it('returns false', () => {
|
||||
describe("updatedDraft", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.updatedDraft).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValue('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValue("true")
|
||||
expect(inputs.updatedDraft).toBe(true)
|
||||
})
|
||||
|
||||
it('returns true when omitted is blank', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValue('true')
|
||||
it("returns true when omitted is blank", () => {
|
||||
mockGetInput.mockReturnValueOnce("").mockReturnValue("true")
|
||||
expect(inputs.updatedDraft).toBe(true)
|
||||
})
|
||||
|
||||
it('returns undefined when omitted for update', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('true')
|
||||
it("returns undefined when omitted for update", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("true")
|
||||
expect(inputs.updatedDraft).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updatedReleaseBody', () => {
|
||||
it('returns input body', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('body')
|
||||
expect(inputs.updatedReleaseBody).toBe('body')
|
||||
describe("updatedReleaseBody", () => {
|
||||
it("returns input body", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("false").mockReturnValueOnce("body")
|
||||
expect(inputs.updatedReleaseBody).toBe("body")
|
||||
})
|
||||
|
||||
it('returns body file contents', () => {
|
||||
it("returns body file contents", () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('a/path')
|
||||
mockReadFileSync.mockReturnValue('file')
|
||||
.mockReturnValueOnce("false")
|
||||
.mockReturnValueOnce("false")
|
||||
.mockReturnValueOnce("")
|
||||
.mockReturnValueOnce("a/path")
|
||||
mockReadFileSync.mockReturnValue("file")
|
||||
|
||||
expect(inputs.updatedReleaseBody).toBe('file')
|
||||
expect(inputs.updatedReleaseBody).toBe("file")
|
||||
})
|
||||
|
||||
it('returns empty', () => {
|
||||
it("returns empty", () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
.mockReturnValueOnce('')
|
||||
expect(inputs.updatedReleaseBody).toBe('')
|
||||
.mockReturnValueOnce("false")
|
||||
.mockReturnValueOnce("false")
|
||||
.mockReturnValueOnce("")
|
||||
.mockReturnValueOnce("")
|
||||
expect(inputs.updatedReleaseBody).toBe("")
|
||||
})
|
||||
|
||||
it('returns undefined when omitted', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('body')
|
||||
it("returns undefined when omitted", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("false").mockReturnValueOnce("body")
|
||||
expect(inputs.updatedReleaseBody).toBeUndefined()
|
||||
})
|
||||
|
||||
it('returns undefined when omitted for update', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('body')
|
||||
it("returns undefined when omitted for update", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("true").mockReturnValueOnce("body")
|
||||
expect(inputs.updatedReleaseBody).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updatedReleaseName', () => {
|
||||
it('returns input name', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('name')
|
||||
expect(inputs.updatedReleaseName).toBe('name')
|
||||
describe("updatedReleaseName", () => {
|
||||
it("returns input name", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("false").mockReturnValueOnce("name")
|
||||
expect(inputs.updatedReleaseName).toBe("name")
|
||||
})
|
||||
|
||||
it('returns undefined when omitted', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('name')
|
||||
it("returns undefined when omitted", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("false").mockReturnValueOnce("name")
|
||||
expect(inputs.updatedReleaseName).toBeUndefined()
|
||||
})
|
||||
|
||||
it('returns undefined when omitted for update', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('name')
|
||||
it("returns undefined when omitted for update", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("true").mockReturnValueOnce("name")
|
||||
expect(inputs.updatedReleaseName).toBeUndefined()
|
||||
})
|
||||
|
||||
it('returns tag', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('')
|
||||
context.ref = 'refs/tags/sha-tag'
|
||||
expect(inputs.updatedReleaseName).toBe('sha-tag')
|
||||
it("returns tag", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("false").mockReturnValueOnce("")
|
||||
context.ref = "refs/tags/sha-tag"
|
||||
expect(inputs.updatedReleaseName).toBe("sha-tag")
|
||||
})
|
||||
})
|
||||
|
||||
describe('updatedPrerelease', () => {
|
||||
it('returns false', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('false')
|
||||
describe("updatedPrerelease", () => {
|
||||
it("returns false", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("false")
|
||||
expect(inputs.updatedPrerelease).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValueOnce("false").mockReturnValueOnce("true")
|
||||
expect(inputs.updatedPrerelease).toBe(true)
|
||||
})
|
||||
|
||||
it('returns undefined when omitted for update', () => {
|
||||
mockGetInput
|
||||
.mockReturnValueOnce('true')
|
||||
.mockReturnValueOnce('false')
|
||||
it("returns undefined when omitted for update", () => {
|
||||
mockGetInput.mockReturnValueOnce("true").mockReturnValueOnce("false")
|
||||
expect(inputs.updatedPrerelease).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateOnlyUnreleased', () => {
|
||||
it('returns false', () => {
|
||||
describe("updateOnlyUnreleased", () => {
|
||||
it("returns false", () => {
|
||||
expect(inputs.updateOnlyUnreleased).toBe(false)
|
||||
})
|
||||
|
||||
it('returns true', () => {
|
||||
mockGetInput.mockReturnValueOnce('true')
|
||||
it("returns true", () => {
|
||||
mockGetInput.mockReturnValueOnce("true")
|
||||
expect(inputs.updateOnlyUnreleased).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -482,7 +424,7 @@ describe('Inputs', () => {
|
||||
function createGlobber(): ArtifactGlobber {
|
||||
const MockGlobber = jest.fn<ArtifactGlobber, any>(() => {
|
||||
return {
|
||||
globArtifactString: mockGlob
|
||||
globArtifactString: mockGlob,
|
||||
}
|
||||
})
|
||||
mockGlob.mockImplementation(() => artifacts)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import {Action} from "../src/Action";
|
||||
import * as github from "@actions/github";
|
||||
import {Inputs} from "../src/Inputs";
|
||||
import {GithubReleases, ReleaseData} from "../src/Releases";
|
||||
import {GithubArtifactUploader} from "../src/ArtifactUploader";
|
||||
import * as path from "path";
|
||||
import {FileArtifactGlobber} from "../src/ArtifactGlobber";
|
||||
import {Outputs} from "../src/Outputs";
|
||||
import {GithubArtifactDestroyer} from "../src/ArtifactDestroyer";
|
||||
import {ReleaseActionSkipper} from "../src/ActionSkipper";
|
||||
import { Action } from "../src/Action"
|
||||
import * as github from "@actions/github"
|
||||
import { Inputs } from "../src/Inputs"
|
||||
import { GithubReleases, ReleaseData } from "../src/Releases"
|
||||
import { GithubArtifactUploader } from "../src/ArtifactUploader"
|
||||
import * as path from "path"
|
||||
import { FileArtifactGlobber } from "../src/ArtifactGlobber"
|
||||
import { Outputs } from "../src/Outputs"
|
||||
import { GithubArtifactDestroyer } from "../src/ArtifactDestroyer"
|
||||
import { ReleaseActionSkipper } from "../src/ActionSkipper"
|
||||
|
||||
// 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
|
||||
// - Remove skip from the test below
|
||||
describe.skip('Integration Test', () => {
|
||||
describe.skip("Integration Test", () => {
|
||||
let action: Action
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -22,18 +22,14 @@ describe.skip('Integration Test', () => {
|
||||
const inputs = getInputs()
|
||||
const outputs = getOutputs()
|
||||
const releases = new GithubReleases(inputs, git)
|
||||
const uploader = new GithubArtifactUploader(
|
||||
releases,
|
||||
inputs.replacesArtifacts,
|
||||
inputs.artifactErrorsFailBuild,
|
||||
)
|
||||
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts, inputs.artifactErrorsFailBuild)
|
||||
const artifactDestroyer = new GithubArtifactDestroyer(releases)
|
||||
const actionSkipper = new ReleaseActionSkipper(inputs.skipIfReleaseExists, releases, inputs.tag)
|
||||
|
||||
action = new Action(inputs, outputs, releases, uploader, artifactDestroyer, actionSkipper)
|
||||
})
|
||||
|
||||
it('Performs action', async () => {
|
||||
it("Performs action", async () => {
|
||||
await action.perform()
|
||||
})
|
||||
|
||||
@@ -47,7 +43,7 @@ describe.skip('Integration Test', () => {
|
||||
createdReleaseBody: "This release was generated by release-action's integration test",
|
||||
createdReleaseName: "Releases Action Integration Test",
|
||||
commit: undefined,
|
||||
discussionCategory: 'Release',
|
||||
discussionCategory: "Release",
|
||||
generateReleaseNotes: true,
|
||||
owner: "ncipollo",
|
||||
createdPrerelease: false,
|
||||
@@ -61,10 +57,10 @@ describe.skip('Integration Test', () => {
|
||||
updatedReleaseBody: "This release was updated by release-action's integration test",
|
||||
updatedReleaseName: "Releases Action Integration Test",
|
||||
updatedPrerelease: false,
|
||||
updateOnlyUnreleased: false
|
||||
updateOnlyUnreleased: false,
|
||||
}
|
||||
})
|
||||
return new MockInputs();
|
||||
return new MockInputs()
|
||||
}
|
||||
|
||||
function getOutputs(): Outputs {
|
||||
@@ -72,7 +68,7 @@ describe.skip('Integration Test', () => {
|
||||
return {
|
||||
applyReleaseData(releaseData: ReleaseData) {
|
||||
console.log(`Release Data: ${releaseData}`)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
return new MockOutputs()
|
||||
@@ -80,7 +76,7 @@ describe.skip('Integration Test', () => {
|
||||
|
||||
function artifacts() {
|
||||
const globber = new FileArtifactGlobber()
|
||||
const artifactPath = path.join(__dirname, 'Integration.test.ts')
|
||||
const artifactPath = path.join(__dirname, "Integration.test.ts")
|
||||
const artifactString = `~/Desktop,~/Desktop/test.txt,blarg.tx, ${artifactPath}`
|
||||
return globber.globArtifactString(artifactString, "raw", false)
|
||||
}
|
||||
@@ -88,5 +84,4 @@ describe.skip('Integration Test', () => {
|
||||
function getToken(): string {
|
||||
return process.env.GITHUB_TOKEN ?? ""
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
const mockSetOutput = jest.fn();
|
||||
const mockSetOutput = jest.fn()
|
||||
|
||||
import {CoreOutputs, Outputs} from "../src/Outputs";
|
||||
import {ReleaseData} from "../src/Releases";
|
||||
import { CoreOutputs, Outputs } from "../src/Outputs"
|
||||
import { ReleaseData } from "../src/Releases"
|
||||
|
||||
jest.mock('@actions/core', () => {
|
||||
return {setOutput: mockSetOutput};
|
||||
jest.mock("@actions/core", () => {
|
||||
return { setOutput: mockSetOutput }
|
||||
})
|
||||
|
||||
describe('Outputs', () => {
|
||||
let outputs: Outputs;
|
||||
describe("Outputs", () => {
|
||||
let outputs: Outputs
|
||||
let releaseData: ReleaseData
|
||||
|
||||
beforeEach(() => {
|
||||
outputs = new CoreOutputs()
|
||||
releaseData = {
|
||||
id: 1,
|
||||
html_url: 'https://api.example.com/assets',
|
||||
upload_url: 'https://api.example.com'
|
||||
html_url: "https://api.example.com/assets",
|
||||
upload_url: "https://api.example.com",
|
||||
}
|
||||
})
|
||||
|
||||
it('Applies the release data to the action output', () => {
|
||||
it("Applies the release data to the action output", () => {
|
||||
outputs.applyReleaseData(releaseData)
|
||||
expect(mockSetOutput).toBeCalledWith('id', releaseData.id)
|
||||
expect(mockSetOutput).toBeCalledWith('html_url', releaseData.html_url)
|
||||
expect(mockSetOutput).toBeCalledWith('upload_url', releaseData.upload_url)
|
||||
expect(mockSetOutput).toBeCalledWith("id", releaseData.id)
|
||||
expect(mockSetOutput).toBeCalledWith("html_url", releaseData.html_url)
|
||||
expect(mockSetOutput).toBeCalledWith("upload_url", releaseData.upload_url)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {ReleaseValidator} from "../src/ReleaseValidator";
|
||||
import { ReleaseValidator } from "../src/ReleaseValidator"
|
||||
|
||||
describe("validateReleaseUpdate", () => {
|
||||
describe("updateOnlyUnreleased is disabled", () => {
|
||||
const validator = new ReleaseValidator(false)
|
||||
it('should not throw', () => {
|
||||
it("should not throw", () => {
|
||||
const releaseResponse = {
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
name: "Name"
|
||||
name: "Name",
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
@@ -16,55 +16,55 @@ describe("validateReleaseUpdate", () => {
|
||||
})
|
||||
describe("updateOnlyUnreleased is enabled", () => {
|
||||
const validator = new ReleaseValidator(true)
|
||||
it('should throw if neither draft or prerelease are enabled', () => {
|
||||
it("should throw if neither draft or prerelease are enabled", () => {
|
||||
const releaseResponse = {
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
name: "Name"
|
||||
name: "Name",
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
}).toThrow()
|
||||
})
|
||||
|
||||
it('should not throw if draft is enabled', () => {
|
||||
it("should not throw if draft is enabled", () => {
|
||||
const releaseResponse = {
|
||||
draft: true,
|
||||
prerelease: false,
|
||||
name: "Name"
|
||||
name: "Name",
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
}).not.toThrow()
|
||||
})
|
||||
|
||||
it('should not throw if prerelease is enabled', () => {
|
||||
it("should not throw if prerelease is enabled", () => {
|
||||
const releaseResponse = {
|
||||
draft: false,
|
||||
prerelease: true,
|
||||
name: "Name"
|
||||
name: "Name",
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
}).not.toThrow()
|
||||
})
|
||||
|
||||
it('should not throw if draft & prerelease is enabled', () => {
|
||||
it("should not throw if draft & prerelease is enabled", () => {
|
||||
const releaseResponse = {
|
||||
draft: true,
|
||||
prerelease: true,
|
||||
name: "Name"
|
||||
name: "Name",
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
}).not.toThrow()
|
||||
})
|
||||
|
||||
it('should default error message release name to release', () => {
|
||||
it("should default error message release name to release", () => {
|
||||
const releaseResponse = {
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
name: null
|
||||
name: null,
|
||||
}
|
||||
expect(() => {
|
||||
validator.validateReleaseUpdate(releaseResponse)
|
||||
|
||||
35
biome.json
Normal file
35
biome.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false,
|
||||
"ignore": ["node_modules/**/*", "dist/"]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"lineEnding": "lf",
|
||||
"indentWidth": 4,
|
||||
"lineWidth": 120
|
||||
},
|
||||
"organizeImports": { "enabled": true },
|
||||
"linter": {
|
||||
"enabled": false,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
"trailingCommas": "es5",
|
||||
"semicolons": "asNeeded",
|
||||
"indentWidth": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
126
dist/index.js
vendored
126
dist/index.js
vendored
@@ -127,7 +127,7 @@ class Action {
|
||||
if (!releases) {
|
||||
throw new Error(`No releases found. Response: ${JSON.stringify(response)}`);
|
||||
}
|
||||
const draftRelease = releases.find(release => release.draft && release.tag_name == tag);
|
||||
const draftRelease = releases.find((release) => release.draft && release.tag_name == tag);
|
||||
return draftRelease?.id;
|
||||
}
|
||||
async createRelease() {
|
||||
@@ -321,14 +321,15 @@ class FileArtifactGlobber {
|
||||
}
|
||||
globArtifactString(artifact, contentType, errorsFailBuild) {
|
||||
const split = /[,\n]/;
|
||||
return artifact.split(split)
|
||||
.map(path => path.trimStart())
|
||||
.map(path => PathNormalizer_1.PathNormalizer.normalizePath(path))
|
||||
.map(path => FileArtifactGlobber.expandPath(path))
|
||||
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
||||
return artifact
|
||||
.split(split)
|
||||
.map((path) => path.trimStart())
|
||||
.map((path) => PathNormalizer_1.PathNormalizer.normalizePath(path))
|
||||
.map((path) => FileArtifactGlobber.expandPath(path))
|
||||
.map((pattern) => this.globPattern(pattern, errorsFailBuild))
|
||||
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
||||
.reduce((accumulated, current) => accumulated.concat(current))
|
||||
.map(path => new Artifact_1.Artifact(path, contentType));
|
||||
.map((path) => new Artifact_1.Artifact(path, contentType));
|
||||
}
|
||||
globPattern(pattern, errorsFailBuild) {
|
||||
const paths = this.globber.glob(pattern);
|
||||
@@ -525,7 +526,7 @@ class GithubArtifactUploader {
|
||||
async deleteUpdatedArtifacts(artifacts, releaseId) {
|
||||
const releaseAssets = await this.releases.listArtifactsForRelease(releaseId);
|
||||
const assetByName = {};
|
||||
releaseAssets.forEach(asset => {
|
||||
releaseAssets.forEach((asset) => {
|
||||
assetByName[asset.name] = asset;
|
||||
});
|
||||
for (const artifact of artifacts) {
|
||||
@@ -616,13 +617,13 @@ class GithubErrorDetail {
|
||||
toString() {
|
||||
const code = this.error.code;
|
||||
switch (code) {
|
||||
case 'missing':
|
||||
case "missing":
|
||||
return this.missingResourceMessage();
|
||||
case 'missing_field':
|
||||
case "missing_field":
|
||||
return this.missingFieldMessage();
|
||||
case 'invalid':
|
||||
case "invalid":
|
||||
return this.invalidFieldMessage();
|
||||
case 'already_exists':
|
||||
case "already_exists":
|
||||
return this.resourceAlreadyExists();
|
||||
default:
|
||||
return this.customErrorMessage();
|
||||
@@ -732,46 +733,45 @@ class CoreInputs {
|
||||
this.context = context;
|
||||
}
|
||||
get allowUpdates() {
|
||||
const allow = core.getInput('allowUpdates');
|
||||
return allow == 'true';
|
||||
const allow = core.getInput("allowUpdates");
|
||||
return allow == "true";
|
||||
}
|
||||
get artifacts() {
|
||||
let artifacts = core.getInput('artifacts');
|
||||
let artifacts = core.getInput("artifacts");
|
||||
if (!artifacts) {
|
||||
artifacts = core.getInput('artifact');
|
||||
artifacts = core.getInput("artifact");
|
||||
}
|
||||
if (artifacts) {
|
||||
let contentType = core.getInput('artifactContentType');
|
||||
let contentType = core.getInput("artifactContentType");
|
||||
if (!contentType) {
|
||||
contentType = 'raw';
|
||||
contentType = "raw";
|
||||
}
|
||||
return this.artifactGlobber
|
||||
.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild);
|
||||
return this.artifactGlobber.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
get artifactErrorsFailBuild() {
|
||||
const allow = core.getInput('artifactErrorsFailBuild');
|
||||
return allow == 'true';
|
||||
const allow = core.getInput("artifactErrorsFailBuild");
|
||||
return allow == "true";
|
||||
}
|
||||
get body() {
|
||||
const body = core.getInput('body');
|
||||
const body = core.getInput("body");
|
||||
if (body) {
|
||||
return body;
|
||||
}
|
||||
const bodyFile = core.getInput('bodyFile');
|
||||
const bodyFile = core.getInput("bodyFile");
|
||||
if (bodyFile) {
|
||||
return this.stringFromFile(bodyFile);
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
get createdDraft() {
|
||||
const draft = core.getInput('draft');
|
||||
return draft == 'true';
|
||||
const draft = core.getInput("draft");
|
||||
return draft == "true";
|
||||
}
|
||||
get createdPrerelease() {
|
||||
const preRelease = core.getInput('prerelease');
|
||||
return preRelease == 'true';
|
||||
const preRelease = core.getInput("prerelease");
|
||||
return preRelease == "true";
|
||||
}
|
||||
get createdReleaseBody() {
|
||||
if (CoreInputs.omitBody)
|
||||
@@ -779,7 +779,7 @@ class CoreInputs {
|
||||
return this.body;
|
||||
}
|
||||
static get omitBody() {
|
||||
return core.getInput('omitBody') == 'true';
|
||||
return core.getInput("omitBody") == "true";
|
||||
}
|
||||
get createdReleaseName() {
|
||||
if (CoreInputs.omitName)
|
||||
@@ -787,57 +787,57 @@ class CoreInputs {
|
||||
return this.name;
|
||||
}
|
||||
static get omitName() {
|
||||
return core.getInput('omitName') == 'true';
|
||||
return core.getInput("omitName") == "true";
|
||||
}
|
||||
get commit() {
|
||||
const commit = core.getInput('commit');
|
||||
const commit = core.getInput("commit");
|
||||
if (commit) {
|
||||
return commit;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
get discussionCategory() {
|
||||
const category = core.getInput('discussionCategory');
|
||||
const category = core.getInput("discussionCategory");
|
||||
if (category) {
|
||||
return category;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
get name() {
|
||||
const name = core.getInput('name');
|
||||
const name = core.getInput("name");
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
return this.tag;
|
||||
}
|
||||
get generateReleaseNotes() {
|
||||
const generate = core.getInput('generateReleaseNotes');
|
||||
return generate == 'true';
|
||||
const generate = core.getInput("generateReleaseNotes");
|
||||
return generate == "true";
|
||||
}
|
||||
get makeLatest() {
|
||||
let latest = core.getInput('makeLatest');
|
||||
let latest = core.getInput("makeLatest");
|
||||
if (latest == "true" || latest == "false" || latest == "legacy") {
|
||||
return latest;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
get owner() {
|
||||
let owner = core.getInput('owner');
|
||||
let owner = core.getInput("owner");
|
||||
if (owner) {
|
||||
return owner;
|
||||
}
|
||||
return this.context.repo.owner;
|
||||
}
|
||||
get removeArtifacts() {
|
||||
const removes = core.getInput('removeArtifacts');
|
||||
return removes == 'true';
|
||||
const removes = core.getInput("removeArtifacts");
|
||||
return removes == "true";
|
||||
}
|
||||
get replacesArtifacts() {
|
||||
const replaces = core.getInput('replacesArtifacts');
|
||||
return replaces == 'true';
|
||||
const replaces = core.getInput("replacesArtifacts");
|
||||
return replaces == "true";
|
||||
}
|
||||
get repo() {
|
||||
let repo = core.getInput('repo');
|
||||
let repo = core.getInput("repo");
|
||||
if (repo) {
|
||||
return repo;
|
||||
}
|
||||
@@ -847,7 +847,7 @@ class CoreInputs {
|
||||
return core.getBooleanInput("skipIfReleaseExists");
|
||||
}
|
||||
get tag() {
|
||||
const tag = core.getInput('tag');
|
||||
const tag = core.getInput("tag");
|
||||
if (tag) {
|
||||
return tag;
|
||||
}
|
||||
@@ -859,7 +859,7 @@ class CoreInputs {
|
||||
throw Error("No tag found in ref or input!");
|
||||
}
|
||||
get token() {
|
||||
return core.getInput('token', { required: true });
|
||||
return core.getInput("token", { required: true });
|
||||
}
|
||||
get updatedDraft() {
|
||||
if (CoreInputs.omitDraftDuringUpdate)
|
||||
@@ -867,7 +867,7 @@ class CoreInputs {
|
||||
return this.createdDraft;
|
||||
}
|
||||
static get omitDraftDuringUpdate() {
|
||||
return core.getInput('omitDraftDuringUpdate') == 'true';
|
||||
return core.getInput("omitDraftDuringUpdate") == "true";
|
||||
}
|
||||
get updatedPrerelease() {
|
||||
if (CoreInputs.omitPrereleaseDuringUpdate)
|
||||
@@ -875,7 +875,7 @@ class CoreInputs {
|
||||
return this.createdPrerelease;
|
||||
}
|
||||
static get omitPrereleaseDuringUpdate() {
|
||||
return core.getInput('omitPrereleaseDuringUpdate') == 'true';
|
||||
return core.getInput("omitPrereleaseDuringUpdate") == "true";
|
||||
}
|
||||
get updatedReleaseBody() {
|
||||
if (CoreInputs.omitBody || CoreInputs.omitBodyDuringUpdate)
|
||||
@@ -883,7 +883,7 @@ class CoreInputs {
|
||||
return this.body;
|
||||
}
|
||||
static get omitBodyDuringUpdate() {
|
||||
return core.getInput('omitBodyDuringUpdate') == 'true';
|
||||
return core.getInput("omitBodyDuringUpdate") == "true";
|
||||
}
|
||||
get updatedReleaseName() {
|
||||
if (CoreInputs.omitName || CoreInputs.omitNameDuringUpdate)
|
||||
@@ -891,13 +891,13 @@ class CoreInputs {
|
||||
return this.name;
|
||||
}
|
||||
get updateOnlyUnreleased() {
|
||||
return core.getInput('updateOnlyUnreleased') == 'true';
|
||||
return core.getInput("updateOnlyUnreleased") == "true";
|
||||
}
|
||||
static get omitNameDuringUpdate() {
|
||||
return core.getInput('omitNameDuringUpdate') == 'true';
|
||||
return core.getInput("omitNameDuringUpdate") == "true";
|
||||
}
|
||||
stringFromFile(path) {
|
||||
return (0, fs_1.readFileSync)(path, 'utf-8');
|
||||
return (0, fs_1.readFileSync)(path, "utf-8");
|
||||
}
|
||||
}
|
||||
exports.CoreInputs = CoreInputs;
|
||||
@@ -948,9 +948,9 @@ exports.CoreOutputs = void 0;
|
||||
const core = __importStar(__nccwpck_require__(1401));
|
||||
class CoreOutputs {
|
||||
applyReleaseData(releaseData) {
|
||||
core.setOutput('id', releaseData.id);
|
||||
core.setOutput('html_url', releaseData.html_url);
|
||||
core.setOutput('upload_url', releaseData.upload_url);
|
||||
core.setOutput("id", releaseData.id);
|
||||
core.setOutput("html_url", releaseData.html_url);
|
||||
core.setOutput("upload_url", releaseData.upload_url);
|
||||
}
|
||||
}
|
||||
exports.CoreOutputs = CoreOutputs;
|
||||
@@ -1032,34 +1032,34 @@ class GithubReleases {
|
||||
prerelease: prerelease,
|
||||
repo: this.inputs.repo,
|
||||
target_commitish: commitHash,
|
||||
tag_name: tag
|
||||
tag_name: tag,
|
||||
});
|
||||
}
|
||||
async deleteArtifact(assetId) {
|
||||
return this.git.rest.repos.deleteReleaseAsset({
|
||||
asset_id: assetId,
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
});
|
||||
}
|
||||
async getByTag(tag) {
|
||||
return this.git.rest.repos.getReleaseByTag({
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo,
|
||||
tag: tag
|
||||
tag: tag,
|
||||
});
|
||||
}
|
||||
async listArtifactsForRelease(releaseId) {
|
||||
return this.git.paginate(this.git.rest.repos.listReleaseAssets, {
|
||||
owner: this.inputs.owner,
|
||||
release_id: releaseId,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
});
|
||||
}
|
||||
async listReleases() {
|
||||
return this.git.rest.repos.listReleases({
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
});
|
||||
}
|
||||
async update(id, tag, body, commitHash, discussionCategory, draft, makeLatest, name, prerelease) {
|
||||
@@ -1075,7 +1075,7 @@ class GithubReleases {
|
||||
prerelease: prerelease,
|
||||
repo: this.inputs.repo,
|
||||
target_commitish: commitHash,
|
||||
tag_name: tag
|
||||
tag_name: tag,
|
||||
});
|
||||
}
|
||||
async uploadArtifact(assetUrl, contentLength, contentType, file, name, releaseId) {
|
||||
@@ -1083,13 +1083,13 @@ class GithubReleases {
|
||||
url: assetUrl,
|
||||
headers: {
|
||||
"content-length": contentLength,
|
||||
"content-type": contentType
|
||||
"content-type": contentType,
|
||||
},
|
||||
data: file,
|
||||
name: name,
|
||||
owner: this.inputs.owner,
|
||||
release_id: releaseId,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1159,7 +1159,7 @@ async function run() {
|
||||
}
|
||||
}
|
||||
function createAction() {
|
||||
const token = core.getInput('token');
|
||||
const token = core.getInput("token");
|
||||
const context = github.context;
|
||||
const git = github.getOctokit(token);
|
||||
const globber = new ArtifactGlobber_1.FileArtifactGlobber();
|
||||
|
||||
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
2187
dist/sourcemap-register.js
vendored
2187
dist/sourcemap-register.js
vendored
File diff suppressed because one or more lines are too long
134
package.json
134
package.json
@@ -1,76 +1,66 @@
|
||||
{
|
||||
"name": "release-action",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"description": "An action which manages a github release",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "rm -rf lib/*",
|
||||
"coverage": "jest --coverage",
|
||||
"debug": "yarn clean && yarn install && yarn build && yarn package",
|
||||
"package": "ncc build --source-map --license licenses.txt",
|
||||
"release": "yarn clean && yarn install --production && yarn build && yarn package",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ncipollo/release-action.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions",
|
||||
"node",
|
||||
"setup"
|
||||
],
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"jest": {
|
||||
"clearMocks": true,
|
||||
"collectCoverage": true,
|
||||
"coveragePathIgnorePatterns": [
|
||||
"src/Globber.ts",
|
||||
"src/Releases.ts"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 95,
|
||||
"functions": 100,
|
||||
"lines": 100,
|
||||
"statements": 100
|
||||
}
|
||||
"name": "release-action",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"description": "An action which manages a github release",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "rm -rf lib/*",
|
||||
"coverage": "jest --coverage",
|
||||
"debug": "yarn clean && yarn install && yarn build && yarn package",
|
||||
"format": "yarn biome format --write .",
|
||||
"package": "ncc build --source-map --license licenses.txt",
|
||||
"release": "yarn clean && yarn install --production && yarn build && yarn package",
|
||||
"test": "jest"
|
||||
},
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"ts"
|
||||
],
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"**/*.test.ts"
|
||||
],
|
||||
"testRunner": "jest-circus/runner",
|
||||
"transform": {
|
||||
"^.+\\.ts$": "ts-jest"
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ncipollo/release-action.git"
|
||||
},
|
||||
"verbose": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"@types/node": "^22.13.4",
|
||||
"glob": "^11.0.1",
|
||||
"untildify": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"jest-cli/yargs": "^17.3.1"
|
||||
}
|
||||
"keywords": ["actions", "node", "setup"],
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"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"
|
||||
},
|
||||
"verbose": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"@types/node": "^22.13.4",
|
||||
"glob": "^11.0.1",
|
||||
"untildify": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"jest-cli/yargs": "^17.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import * as core from '@actions/core';
|
||||
import {Inputs} from "./Inputs";
|
||||
import * as core from "@actions/core"
|
||||
import { Inputs } from "./Inputs"
|
||||
import {
|
||||
CreateOrUpdateReleaseResponse,
|
||||
CreateReleaseResponse,
|
||||
ReleaseByTagResponse,
|
||||
Releases,
|
||||
UpdateReleaseResponse
|
||||
} from "./Releases";
|
||||
import {ArtifactUploader} from "./ArtifactUploader";
|
||||
import {GithubError} from "./GithubError";
|
||||
import {Outputs} from "./Outputs";
|
||||
import {ArtifactDestroyer} from "./ArtifactDestroyer";
|
||||
import {ReleaseValidator} from "./ReleaseValidator";
|
||||
import {ActionSkipper} from "./ActionSkipper";
|
||||
UpdateReleaseResponse,
|
||||
} from "./Releases"
|
||||
import { ArtifactUploader } from "./ArtifactUploader"
|
||||
import { GithubError } from "./GithubError"
|
||||
import { Outputs } from "./Outputs"
|
||||
import { ArtifactDestroyer } from "./ArtifactDestroyer"
|
||||
import { ReleaseValidator } from "./ReleaseValidator"
|
||||
import { ActionSkipper } from "./ActionSkipper"
|
||||
|
||||
export class Action {
|
||||
private inputs: Inputs
|
||||
@@ -24,12 +24,14 @@ export class Action {
|
||||
|
||||
private releaseValidator: ReleaseValidator
|
||||
|
||||
constructor(inputs: Inputs,
|
||||
outputs: Outputs,
|
||||
releases: Releases,
|
||||
uploader: ArtifactUploader,
|
||||
artifactDestroyer: ArtifactDestroyer,
|
||||
skipper: ActionSkipper) {
|
||||
constructor(
|
||||
inputs: Inputs,
|
||||
outputs: Outputs,
|
||||
releases: Releases,
|
||||
uploader: ArtifactUploader,
|
||||
artifactDestroyer: ArtifactDestroyer,
|
||||
skipper: ActionSkipper
|
||||
) {
|
||||
this.inputs = inputs
|
||||
this.outputs = outputs
|
||||
this.releases = releases
|
||||
@@ -45,7 +47,7 @@ export class Action {
|
||||
return
|
||||
}
|
||||
|
||||
const releaseResponse = await this.createOrUpdateRelease();
|
||||
const releaseResponse = await this.createOrUpdateRelease()
|
||||
const releaseData = releaseResponse.data
|
||||
const releaseId = releaseData.id
|
||||
const uploadUrl = releaseData.upload_url
|
||||
@@ -120,11 +122,11 @@ export class Action {
|
||||
const tag = this.inputs.tag
|
||||
const response = await this.releases.listReleases()
|
||||
const releases = response.data
|
||||
if(!releases) {
|
||||
if (!releases) {
|
||||
throw new Error(`No releases found. Response: ${JSON.stringify(response)}`)
|
||||
}
|
||||
|
||||
const draftRelease = releases.find(release => release.draft && release.tag_name == tag)
|
||||
const draftRelease = releases.find((release) => release.draft && release.tag_name == tag)
|
||||
|
||||
return draftRelease?.id
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import {Releases} from "./Releases";
|
||||
import { Releases } from "./Releases"
|
||||
|
||||
export interface ActionSkipper {
|
||||
shouldSkip(): Promise<boolean>
|
||||
}
|
||||
|
||||
export class ReleaseActionSkipper {
|
||||
constructor(private skipIfReleaseExists: boolean,
|
||||
private releases: Releases,
|
||||
private tag: string) {
|
||||
}
|
||||
constructor(
|
||||
private skipIfReleaseExists: boolean,
|
||||
private releases: Releases,
|
||||
private tag: string
|
||||
) {}
|
||||
|
||||
async shouldSkip(): Promise<boolean> {
|
||||
if (!this.skipIfReleaseExists) {
|
||||
// Bail if skip flag isn't set.
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -21,7 +22,7 @@ export class ReleaseActionSkipper {
|
||||
return getResponse.data != null
|
||||
} catch (error: any) {
|
||||
// There is either no release or something else went wrong. Either way, run the action.
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { basename } from "path";
|
||||
import {createReadStream, readFileSync, ReadStream, statSync} from "fs";
|
||||
import { basename } from "path"
|
||||
import { createReadStream, readFileSync, ReadStream, statSync } from "fs"
|
||||
|
||||
export class Artifact {
|
||||
readonly contentType: string
|
||||
@@ -9,7 +9,7 @@ export class Artifact {
|
||||
constructor(path: string, contentType: string = "raw") {
|
||||
this.path = path
|
||||
this.name = basename(path)
|
||||
this.contentType = contentType;
|
||||
this.contentType = contentType
|
||||
}
|
||||
|
||||
get contentLength(): number {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {Releases} from "./Releases";
|
||||
import * as core from "@actions/core";
|
||||
import { Releases } from "./Releases"
|
||||
import * as core from "@actions/core"
|
||||
|
||||
export interface ArtifactDestroyer {
|
||||
destroyArtifacts(releaseId: number): Promise<void>
|
||||
}
|
||||
|
||||
export class GithubArtifactDestroyer implements ArtifactDestroyer {
|
||||
constructor(private releases: Releases) {
|
||||
}
|
||||
constructor(private releases: Releases) {}
|
||||
|
||||
async destroyArtifacts(releaseId: number): Promise<void> {
|
||||
const releaseAssets = await this.releases.listArtifactsForRelease(releaseId)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as core from '@actions/core';
|
||||
import {Globber, FileGlobber} from "./Globber";
|
||||
import {Artifact} from "./Artifact";
|
||||
import untildify from "untildify";
|
||||
import {ArtifactPathValidator} from "./ArtifactPathValidator";
|
||||
import {PathNormalizer} from "./PathNormalizer";
|
||||
import * as core from "@actions/core"
|
||||
import { Globber, FileGlobber } from "./Globber"
|
||||
import { Artifact } from "./Artifact"
|
||||
import untildify from "untildify"
|
||||
import { ArtifactPathValidator } from "./ArtifactPathValidator"
|
||||
import { PathNormalizer } from "./PathNormalizer"
|
||||
|
||||
export interface ArtifactGlobber {
|
||||
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[]
|
||||
@@ -18,14 +18,15 @@ export class FileArtifactGlobber implements ArtifactGlobber {
|
||||
|
||||
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[] {
|
||||
const split = /[,\n]/
|
||||
return artifact.split(split)
|
||||
.map(path => path.trimStart())
|
||||
.map(path => PathNormalizer.normalizePath(path))
|
||||
.map(path => FileArtifactGlobber.expandPath(path))
|
||||
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
||||
return artifact
|
||||
.split(split)
|
||||
.map((path) => path.trimStart())
|
||||
.map((path) => PathNormalizer.normalizePath(path))
|
||||
.map((path) => FileArtifactGlobber.expandPath(path))
|
||||
.map((pattern) => this.globPattern(pattern, errorsFailBuild))
|
||||
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
||||
.reduce((accumulated, current) => accumulated.concat(current))
|
||||
.map(path => new Artifact(path, contentType))
|
||||
.map((path) => new Artifact(path, contentType))
|
||||
}
|
||||
|
||||
private globPattern(pattern: string, errorsFailBuild: boolean): [string, string[]] {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import * as core from "@actions/core";
|
||||
import {statSync} from "fs";
|
||||
import * as core from "@actions/core"
|
||||
import { statSync } from "fs"
|
||||
|
||||
export class ArtifactPathValidator {
|
||||
private readonly errorsFailBuild: boolean;
|
||||
private paths: string[];
|
||||
private readonly errorsFailBuild: boolean
|
||||
private paths: string[]
|
||||
private readonly pattern: string
|
||||
|
||||
constructor(errorsFailBuild: boolean, paths: string[], pattern: string) {
|
||||
this.paths = paths;
|
||||
this.paths = paths
|
||||
this.pattern = pattern
|
||||
this.errorsFailBuild = errorsFailBuild;
|
||||
this.errorsFailBuild = errorsFailBuild
|
||||
}
|
||||
|
||||
validate(): string[] {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core';
|
||||
import {Artifact} from "./Artifact";
|
||||
import {Releases} from "./Releases";
|
||||
import * as core from "@actions/core"
|
||||
import { Artifact } from "./Artifact"
|
||||
import { Releases } from "./Releases"
|
||||
|
||||
export interface ArtifactUploader {
|
||||
uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<void>
|
||||
@@ -10,13 +10,10 @@ export class GithubArtifactUploader implements ArtifactUploader {
|
||||
constructor(
|
||||
private releases: Releases,
|
||||
private replacesExistingArtifacts: boolean = true,
|
||||
private throwsUploadErrors: boolean = false,
|
||||
) {
|
||||
}
|
||||
private throwsUploadErrors: boolean = false
|
||||
) {}
|
||||
|
||||
async uploadArtifacts(artifacts: Artifact[],
|
||||
releaseId: number,
|
||||
uploadUrl: string): Promise<void> {
|
||||
async uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<void> {
|
||||
if (this.replacesExistingArtifacts) {
|
||||
await this.deleteUpdatedArtifacts(artifacts, releaseId)
|
||||
}
|
||||
@@ -25,18 +22,17 @@ export class GithubArtifactUploader implements ArtifactUploader {
|
||||
}
|
||||
}
|
||||
|
||||
private async uploadArtifact(artifact: Artifact,
|
||||
releaseId: number,
|
||||
uploadUrl: string,
|
||||
retry = 3) {
|
||||
private async uploadArtifact(artifact: Artifact, releaseId: number, uploadUrl: string, retry = 3) {
|
||||
try {
|
||||
core.debug(`Uploading artifact ${artifact.name}...`)
|
||||
await this.releases.uploadArtifact(uploadUrl,
|
||||
await this.releases.uploadArtifact(
|
||||
uploadUrl,
|
||||
artifact.contentLength,
|
||||
artifact.contentType,
|
||||
artifact.readFile(),
|
||||
artifact.name,
|
||||
releaseId)
|
||||
releaseId
|
||||
)
|
||||
} catch (error: any) {
|
||||
if (error.status >= 500 && retry > 0) {
|
||||
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}. Retrying...`)
|
||||
@@ -54,9 +50,9 @@ export class GithubArtifactUploader implements ArtifactUploader {
|
||||
private async deleteUpdatedArtifacts(artifacts: Artifact[], releaseId: number): Promise<void> {
|
||||
const releaseAssets = await this.releases.listArtifactsForRelease(releaseId)
|
||||
const assetByName: Record<string, { id: number; name: string }> = {}
|
||||
releaseAssets.forEach(asset => {
|
||||
releaseAssets.forEach((asset) => {
|
||||
assetByName[asset.name] = asset
|
||||
});
|
||||
})
|
||||
for (const artifact of artifacts) {
|
||||
const asset = assetByName[artifact.name]
|
||||
if (asset) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {GithubErrorDetail} from "./GithubErrorDetail"
|
||||
import { GithubErrorDetail } from "./GithubErrorDetail"
|
||||
|
||||
export class GithubError {
|
||||
private error: any
|
||||
@@ -48,4 +48,3 @@ export class GithubError {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export class GithubErrorDetail {
|
||||
private error: any;
|
||||
private error: any
|
||||
|
||||
constructor(error: any) {
|
||||
this.error = error
|
||||
@@ -12,13 +12,13 @@ export class GithubErrorDetail {
|
||||
toString(): string {
|
||||
const code = this.error.code
|
||||
switch (code) {
|
||||
case 'missing':
|
||||
case "missing":
|
||||
return this.missingResourceMessage()
|
||||
case 'missing_field':
|
||||
case "missing_field":
|
||||
return this.missingFieldMessage()
|
||||
case 'invalid':
|
||||
case "invalid":
|
||||
return this.invalidFieldMessage()
|
||||
case 'already_exists':
|
||||
case "already_exists":
|
||||
return this.resourceAlreadyExists()
|
||||
default:
|
||||
return this.customErrorMessage()
|
||||
@@ -26,7 +26,7 @@ export class GithubErrorDetail {
|
||||
}
|
||||
|
||||
private customErrorMessage(): string {
|
||||
const message = this.error.message;
|
||||
const message = this.error.message
|
||||
const documentation = this.error.documentation_url
|
||||
|
||||
let documentationMessage: string
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {globSync} from "glob";
|
||||
|
||||
import { globSync } from "glob"
|
||||
|
||||
export interface Globber {
|
||||
glob(pattern: string): string[]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as core from '@actions/core';
|
||||
import {Context} from "@actions/github/lib/context";
|
||||
import {readFileSync} from 'fs';
|
||||
import {ArtifactGlobber} from './ArtifactGlobber';
|
||||
import {Artifact} from './Artifact';
|
||||
import * as core from "@actions/core"
|
||||
import { Context } from "@actions/github/lib/context"
|
||||
import { readFileSync } from "fs"
|
||||
import { ArtifactGlobber } from "./ArtifactGlobber"
|
||||
import { Artifact } from "./Artifact"
|
||||
|
||||
export interface Inputs {
|
||||
readonly allowUpdates: boolean
|
||||
@@ -40,53 +40,52 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get allowUpdates(): boolean {
|
||||
const allow = core.getInput('allowUpdates')
|
||||
return allow == 'true'
|
||||
const allow = core.getInput("allowUpdates")
|
||||
return allow == "true"
|
||||
}
|
||||
|
||||
get artifacts(): Artifact[] {
|
||||
let artifacts = core.getInput('artifacts')
|
||||
let artifacts = core.getInput("artifacts")
|
||||
if (!artifacts) {
|
||||
artifacts = core.getInput('artifact')
|
||||
artifacts = core.getInput("artifact")
|
||||
}
|
||||
if (artifacts) {
|
||||
let contentType = core.getInput('artifactContentType')
|
||||
let contentType = core.getInput("artifactContentType")
|
||||
if (!contentType) {
|
||||
contentType = 'raw'
|
||||
contentType = "raw"
|
||||
}
|
||||
return this.artifactGlobber
|
||||
.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild)
|
||||
return this.artifactGlobber.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
get artifactErrorsFailBuild(): boolean {
|
||||
const allow = core.getInput('artifactErrorsFailBuild')
|
||||
return allow == 'true'
|
||||
const allow = core.getInput("artifactErrorsFailBuild")
|
||||
return allow == "true"
|
||||
}
|
||||
|
||||
private get body(): string | undefined {
|
||||
const body = core.getInput('body')
|
||||
const body = core.getInput("body")
|
||||
if (body) {
|
||||
return body
|
||||
}
|
||||
|
||||
const bodyFile = core.getInput('bodyFile')
|
||||
const bodyFile = core.getInput("bodyFile")
|
||||
if (bodyFile) {
|
||||
return this.stringFromFile(bodyFile)
|
||||
}
|
||||
|
||||
return ''
|
||||
return ""
|
||||
}
|
||||
|
||||
get createdDraft(): boolean {
|
||||
const draft = core.getInput('draft')
|
||||
return draft == 'true'
|
||||
const draft = core.getInput("draft")
|
||||
return draft == "true"
|
||||
}
|
||||
|
||||
get createdPrerelease(): boolean {
|
||||
const preRelease = core.getInput('prerelease')
|
||||
return preRelease == 'true'
|
||||
const preRelease = core.getInput("prerelease")
|
||||
return preRelease == "true"
|
||||
}
|
||||
|
||||
get createdReleaseBody(): string | undefined {
|
||||
@@ -95,7 +94,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private static get omitBody(): boolean {
|
||||
return core.getInput('omitBody') == 'true'
|
||||
return core.getInput("omitBody") == "true"
|
||||
}
|
||||
|
||||
get createdReleaseName(): string | undefined {
|
||||
@@ -104,11 +103,11 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private static get omitName(): boolean {
|
||||
return core.getInput('omitName') == 'true'
|
||||
return core.getInput("omitName") == "true"
|
||||
}
|
||||
|
||||
get commit(): string | undefined {
|
||||
const commit = core.getInput('commit')
|
||||
const commit = core.getInput("commit")
|
||||
if (commit) {
|
||||
return commit
|
||||
}
|
||||
@@ -116,7 +115,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get discussionCategory(): string | undefined {
|
||||
const category = core.getInput('discussionCategory')
|
||||
const category = core.getInput("discussionCategory")
|
||||
if (category) {
|
||||
return category
|
||||
}
|
||||
@@ -124,7 +123,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private get name(): string | undefined {
|
||||
const name = core.getInput('name')
|
||||
const name = core.getInput("name")
|
||||
if (name) {
|
||||
return name
|
||||
}
|
||||
@@ -133,21 +132,21 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get generateReleaseNotes(): boolean {
|
||||
const generate = core.getInput('generateReleaseNotes')
|
||||
return generate == 'true'
|
||||
const generate = core.getInput("generateReleaseNotes")
|
||||
return generate == "true"
|
||||
}
|
||||
|
||||
get makeLatest(): "legacy" | "true" | "false" | undefined {
|
||||
let latest = core.getInput('makeLatest')
|
||||
let latest = core.getInput("makeLatest")
|
||||
if (latest == "true" || latest == "false" || latest == "legacy") {
|
||||
return latest;
|
||||
return latest
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
get owner(): string {
|
||||
let owner = core.getInput('owner')
|
||||
let owner = core.getInput("owner")
|
||||
if (owner) {
|
||||
return owner
|
||||
}
|
||||
@@ -155,17 +154,17 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get removeArtifacts(): boolean {
|
||||
const removes = core.getInput('removeArtifacts')
|
||||
return removes == 'true'
|
||||
const removes = core.getInput("removeArtifacts")
|
||||
return removes == "true"
|
||||
}
|
||||
|
||||
get replacesArtifacts(): boolean {
|
||||
const replaces = core.getInput('replacesArtifacts')
|
||||
return replaces == 'true'
|
||||
const replaces = core.getInput("replacesArtifacts")
|
||||
return replaces == "true"
|
||||
}
|
||||
|
||||
get repo(): string {
|
||||
let repo = core.getInput('repo')
|
||||
let repo = core.getInput("repo")
|
||||
if (repo) {
|
||||
return repo
|
||||
}
|
||||
@@ -177,9 +176,9 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get tag(): string {
|
||||
const tag = core.getInput('tag')
|
||||
const tag = core.getInput("tag")
|
||||
if (tag) {
|
||||
return tag;
|
||||
return tag
|
||||
}
|
||||
|
||||
const ref = this.context.ref
|
||||
@@ -192,7 +191,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get token(): string {
|
||||
return core.getInput('token', {required: true})
|
||||
return core.getInput("token", { required: true })
|
||||
}
|
||||
|
||||
get updatedDraft(): boolean | undefined {
|
||||
@@ -201,7 +200,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private static get omitDraftDuringUpdate(): boolean {
|
||||
return core.getInput('omitDraftDuringUpdate') == 'true'
|
||||
return core.getInput("omitDraftDuringUpdate") == "true"
|
||||
}
|
||||
|
||||
get updatedPrerelease(): boolean | undefined {
|
||||
@@ -210,7 +209,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private static get omitPrereleaseDuringUpdate(): boolean {
|
||||
return core.getInput('omitPrereleaseDuringUpdate') == 'true'
|
||||
return core.getInput("omitPrereleaseDuringUpdate") == "true"
|
||||
}
|
||||
|
||||
get updatedReleaseBody(): string | undefined {
|
||||
@@ -219,7 +218,7 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
private static get omitBodyDuringUpdate(): boolean {
|
||||
return core.getInput('omitBodyDuringUpdate') == 'true'
|
||||
return core.getInput("omitBodyDuringUpdate") == "true"
|
||||
}
|
||||
|
||||
get updatedReleaseName(): string | undefined {
|
||||
@@ -228,14 +227,14 @@ export class CoreInputs implements Inputs {
|
||||
}
|
||||
|
||||
get updateOnlyUnreleased(): boolean {
|
||||
return core.getInput('updateOnlyUnreleased') == 'true'
|
||||
return core.getInput("updateOnlyUnreleased") == "true"
|
||||
}
|
||||
|
||||
private static get omitNameDuringUpdate(): boolean {
|
||||
return core.getInput('omitNameDuringUpdate') == 'true'
|
||||
return core.getInput("omitNameDuringUpdate") == "true"
|
||||
}
|
||||
|
||||
stringFromFile(path: string): string {
|
||||
return readFileSync(path, 'utf-8')
|
||||
return readFileSync(path, "utf-8")
|
||||
}
|
||||
}
|
||||
|
||||
28
src/Main.ts
28
src/Main.ts
@@ -1,14 +1,14 @@
|
||||
import * as github from '@actions/github';
|
||||
import * as core from '@actions/core';
|
||||
import {CoreInputs} from './Inputs';
|
||||
import {GithubReleases} from './Releases';
|
||||
import {Action} from './Action';
|
||||
import {GithubArtifactUploader} from './ArtifactUploader';
|
||||
import {FileArtifactGlobber} from './ArtifactGlobber';
|
||||
import {GithubError} from './GithubError';
|
||||
import {CoreOutputs} from "./Outputs";
|
||||
import {GithubArtifactDestroyer} from "./ArtifactDestroyer";
|
||||
import {ActionSkipper, ReleaseActionSkipper} from "./ActionSkipper";
|
||||
import * as github from "@actions/github"
|
||||
import * as core from "@actions/core"
|
||||
import { CoreInputs } from "./Inputs"
|
||||
import { GithubReleases } from "./Releases"
|
||||
import { Action } from "./Action"
|
||||
import { GithubArtifactUploader } from "./ArtifactUploader"
|
||||
import { FileArtifactGlobber } from "./ArtifactGlobber"
|
||||
import { GithubError } from "./GithubError"
|
||||
import { CoreOutputs } from "./Outputs"
|
||||
import { GithubArtifactDestroyer } from "./ArtifactDestroyer"
|
||||
import { ActionSkipper, ReleaseActionSkipper } from "./ActionSkipper"
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
@@ -16,12 +16,12 @@ async function run() {
|
||||
await action.perform()
|
||||
} catch (error) {
|
||||
const githubError = new GithubError(error)
|
||||
core.setFailed(githubError.toString());
|
||||
core.setFailed(githubError.toString())
|
||||
}
|
||||
}
|
||||
|
||||
function createAction(): Action {
|
||||
const token = core.getInput('token')
|
||||
const token = core.getInput("token")
|
||||
const context = github.context
|
||||
const git = github.getOctokit(token)
|
||||
const globber = new FileArtifactGlobber()
|
||||
@@ -36,4 +36,4 @@ function createAction(): Action {
|
||||
return new Action(inputs, outputs, releases, uploader, artifactDestroyer, skipper)
|
||||
}
|
||||
|
||||
run();
|
||||
run()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as core from '@actions/core';
|
||||
import {ReleaseData} from "./Releases";
|
||||
import * as core from "@actions/core"
|
||||
import { ReleaseData } from "./Releases"
|
||||
|
||||
export interface Outputs {
|
||||
applyReleaseData(releaseData: ReleaseData): void
|
||||
@@ -7,8 +7,8 @@ export interface Outputs {
|
||||
|
||||
export class CoreOutputs implements Outputs {
|
||||
applyReleaseData(releaseData: ReleaseData) {
|
||||
core.setOutput('id', releaseData.id)
|
||||
core.setOutput('html_url', releaseData.html_url)
|
||||
core.setOutput('upload_url', releaseData.upload_url)
|
||||
core.setOutput("id", releaseData.id)
|
||||
core.setOutput("html_url", releaseData.html_url)
|
||||
core.setOutput("upload_url", releaseData.upload_url)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import path from "path";
|
||||
import path from "path"
|
||||
|
||||
export class PathNormalizer {
|
||||
static normalizePath(pathString: string): string {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export class ReleaseValidator {
|
||||
constructor(private updateOnlyUnreleased: boolean) {
|
||||
}
|
||||
constructor(private updateOnlyUnreleased: boolean) {}
|
||||
|
||||
validateReleaseUpdate(releaseResponse: ReleaseStageArguments) {
|
||||
if (!this.updateOnlyUnreleased) {
|
||||
@@ -8,7 +7,9 @@ export class ReleaseValidator {
|
||||
}
|
||||
|
||||
if (!releaseResponse.draft && !releaseResponse.prerelease) {
|
||||
throw new Error(`Tried to update "${releaseResponse.name ?? "release"}" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`)
|
||||
throw new Error(
|
||||
`Tried to update "${releaseResponse.name ?? "release"}" which is neither a draft or prerelease. (updateOnlyUnreleased is on)`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {GitHub} from '@actions/github/lib/utils'
|
||||
import {OctokitResponse} from "@octokit/types";
|
||||
import {RestEndpointMethodTypes} from "@octokit/plugin-rest-endpoint-methods";
|
||||
import {Inputs} from "./Inputs";
|
||||
import { GitHub } from "@actions/github/lib/utils"
|
||||
import { OctokitResponse } from "@octokit/types"
|
||||
import { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods"
|
||||
import { Inputs } from "./Inputs"
|
||||
|
||||
export type CreateReleaseResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"]
|
||||
export type ReleaseByTagResponse = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"]
|
||||
@@ -25,7 +25,7 @@ export interface Releases {
|
||||
discussionCategory?: string,
|
||||
draft?: boolean,
|
||||
generateReleaseNotes?: boolean,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
name?: string,
|
||||
prerelease?: boolean
|
||||
): Promise<CreateReleaseResponse>
|
||||
@@ -45,7 +45,7 @@ export interface Releases {
|
||||
commitHash?: string,
|
||||
discussionCategory?: string,
|
||||
draft?: boolean,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
name?: string,
|
||||
prerelease?: boolean
|
||||
): Promise<UpdateReleaseResponse>
|
||||
@@ -56,7 +56,7 @@ export interface Releases {
|
||||
contentType: string,
|
||||
file: string | object,
|
||||
name: string,
|
||||
releaseId: number,
|
||||
releaseId: number
|
||||
): Promise<UploadArtifactResponse>
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export class GithubReleases implements Releases {
|
||||
discussionCategory?: string,
|
||||
draft?: boolean,
|
||||
generateReleaseNotes?: boolean,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
name?: string,
|
||||
prerelease?: boolean
|
||||
): Promise<CreateReleaseResponse> {
|
||||
@@ -92,17 +92,15 @@ export class GithubReleases implements Releases {
|
||||
prerelease: prerelease,
|
||||
repo: this.inputs.repo,
|
||||
target_commitish: commitHash,
|
||||
tag_name: tag
|
||||
tag_name: tag,
|
||||
})
|
||||
}
|
||||
|
||||
async deleteArtifact(
|
||||
assetId: number
|
||||
): Promise<OctokitResponse<any>> {
|
||||
async deleteArtifact(assetId: number): Promise<OctokitResponse<any>> {
|
||||
return this.git.rest.repos.deleteReleaseAsset({
|
||||
asset_id: assetId,
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -110,24 +108,22 @@ export class GithubReleases implements Releases {
|
||||
return this.git.rest.repos.getReleaseByTag({
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo,
|
||||
tag: tag
|
||||
tag: tag,
|
||||
})
|
||||
}
|
||||
|
||||
async listArtifactsForRelease(
|
||||
releaseId: number
|
||||
): Promise<ListReleaseAssetsResponseData> {
|
||||
async listArtifactsForRelease(releaseId: number): Promise<ListReleaseAssetsResponseData> {
|
||||
return this.git.paginate(this.git.rest.repos.listReleaseAssets, {
|
||||
owner: this.inputs.owner,
|
||||
release_id: releaseId,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
})
|
||||
}
|
||||
|
||||
async listReleases(): Promise<ListReleasesResponse> {
|
||||
return this.git.rest.repos.listReleases({
|
||||
owner: this.inputs.owner,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -138,7 +134,7 @@ export class GithubReleases implements Releases {
|
||||
commitHash?: string,
|
||||
discussionCategory?: string,
|
||||
draft?: boolean,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
makeLatest?: "legacy" | "true" | "false" | undefined,
|
||||
name?: string,
|
||||
prerelease?: boolean
|
||||
): Promise<UpdateReleaseResponse> {
|
||||
@@ -154,7 +150,7 @@ export class GithubReleases implements Releases {
|
||||
prerelease: prerelease,
|
||||
repo: this.inputs.repo,
|
||||
target_commitish: commitHash,
|
||||
tag_name: tag
|
||||
tag_name: tag,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -164,19 +160,19 @@ export class GithubReleases implements Releases {
|
||||
contentType: string,
|
||||
file: string | object,
|
||||
name: string,
|
||||
releaseId: number,
|
||||
releaseId: number
|
||||
): Promise<UploadArtifactResponse> {
|
||||
return this.git.rest.repos.uploadReleaseAsset({
|
||||
url: assetUrl,
|
||||
headers: {
|
||||
"content-length": contentLength,
|
||||
"content-type": contentType
|
||||
"content-type": contentType,
|
||||
},
|
||||
data: file as any,
|
||||
name: name,
|
||||
owner: this.inputs.owner,
|
||||
release_id: releaseId,
|
||||
repo: this.inputs.repo
|
||||
repo: this.inputs.repo,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"skipLibCheck": true,
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noImplicitAny": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
85
yarn.lock
85
yarn.lock
@@ -571,6 +571,60 @@
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@biomejs/biome@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-1.9.4.tgz#89766281cbc3a0aae865a7ff13d6aaffea2842bf"
|
||||
integrity sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==
|
||||
optionalDependencies:
|
||||
"@biomejs/cli-darwin-arm64" "1.9.4"
|
||||
"@biomejs/cli-darwin-x64" "1.9.4"
|
||||
"@biomejs/cli-linux-arm64" "1.9.4"
|
||||
"@biomejs/cli-linux-arm64-musl" "1.9.4"
|
||||
"@biomejs/cli-linux-x64" "1.9.4"
|
||||
"@biomejs/cli-linux-x64-musl" "1.9.4"
|
||||
"@biomejs/cli-win32-arm64" "1.9.4"
|
||||
"@biomejs/cli-win32-x64" "1.9.4"
|
||||
|
||||
"@biomejs/cli-darwin-arm64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz#dfa376d23a54a2d8f17133c92f23c1bf2e62509f"
|
||||
integrity sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==
|
||||
|
||||
"@biomejs/cli-darwin-x64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz#eafc2ce3849d385fc02238aad1ca4a73395a64d9"
|
||||
integrity sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz#d780c3e01758fc90f3268357e3f19163d1f84fca"
|
||||
integrity sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==
|
||||
|
||||
"@biomejs/cli-linux-arm64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz#8ed1dd0e89419a4b66a47f95aefb8c46ae6041c9"
|
||||
integrity sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==
|
||||
|
||||
"@biomejs/cli-linux-x64-musl@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz#f36982b966bd671a36671e1de4417963d7db15fb"
|
||||
integrity sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==
|
||||
|
||||
"@biomejs/cli-linux-x64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz#a0a7f56680c76b8034ddc149dbf398bdd3a462e8"
|
||||
integrity sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==
|
||||
|
||||
"@biomejs/cli-win32-arm64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz#e2ef4e0084e76b7e26f0fc887c5ef1265ea56200"
|
||||
integrity sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==
|
||||
|
||||
"@biomejs/cli-win32-x64@1.9.4":
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz#4c7afa90e3970213599b4095e62f87e5972b2340"
|
||||
integrity sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==
|
||||
|
||||
"@fastify/busboy@^2.0.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff"
|
||||
@@ -2624,7 +2678,7 @@ string-length@^4.0.1:
|
||||
char-regex "^1.0.2"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -2642,15 +2696,6 @@ string-width@^4.1.0, string-width@^4.2.0:
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^5.0.1, string-width@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
@@ -2660,7 +2705,7 @@ string-width@^5.0.1, string-width@^5.1.2:
|
||||
emoji-regex "^9.2.2"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@@ -2674,13 +2719,6 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.1:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
|
||||
@@ -2830,16 +2868,7 @@ which@^2.0.1:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
|
||||
Reference in New Issue
Block a user