Fixes #474 Regenerate release notes on release updates (#497)

This commit is contained in:
Radek Antoniuk
2025-02-20 15:11:25 +01:00
committed by GitHub
parent 62f16c02e7
commit a8c5a7f252
11 changed files with 952 additions and 3059 deletions

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules/ node_modules/
__tests__/runner/* __tests__/runner/*
.DS_Store
# Created by https://www.gitignore.io/api/webstorm # Created by https://www.gitignore.io/api/webstorm
# Edit at https://www.gitignore.io/?templates=webstorm # Edit at https://www.gitignore.io/?templates=webstorm

View File

@@ -1,11 +1,11 @@
import { Action } from "../src/Action" import { Action } from "../src/Action"
import type { ActionSkipper } from "../src/ActionSkipper"
import { Artifact } from "../src/Artifact" import { Artifact } from "../src/Artifact"
import { Inputs } from "../src/Inputs" import type { ArtifactDestroyer } from "../src/ArtifactDestroyer"
import { Releases } from "../src/Releases" import type { ArtifactUploader } from "../src/ArtifactUploader"
import { ArtifactUploader } from "../src/ArtifactUploader" import type { Inputs } from "../src/Inputs"
import { Outputs } from "../src/Outputs" import type { Outputs } from "../src/Outputs"
import { ArtifactDestroyer } from "../src/ArtifactDestroyer" import type { Releases } from "../src/Releases"
import { ActionSkipper } from "../src/ActionSkipper"
const applyReleaseDataMock = jest.fn() const applyReleaseDataMock = jest.fn()
const artifactDestroyMock = jest.fn() const artifactDestroyMock = jest.fn()
@@ -17,6 +17,7 @@ const listMock = jest.fn()
const shouldSkipMock = jest.fn() const shouldSkipMock = jest.fn()
const updateMock = jest.fn() const updateMock = jest.fn()
const uploadMock = jest.fn() const uploadMock = jest.fn()
const genReleaseNotesMock = jest.fn()
const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")] const artifacts = [new Artifact("a/art1"), new Artifact("b/art2")]
@@ -39,6 +40,7 @@ const updatePrerelease = false
const updateOnlyUnreleased = false const updateOnlyUnreleased = false
const url = "http://api.example.com" const url = "http://api.example.com"
const makeLatest = "legacy" const makeLatest = "legacy"
const generatedReleaseBody = "test release notes"
describe("Action", () => { describe("Action", () => {
beforeEach(() => { beforeEach(() => {
@@ -55,7 +57,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -66,7 +68,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toHaveBeenCalled()
assertOutputApplied() assertOutputApplied()
}) })
@@ -77,7 +79,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -88,7 +90,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
}) })
@@ -102,7 +104,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -113,7 +115,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
}) })
@@ -122,7 +124,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -133,7 +135,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
}) })
@@ -142,7 +144,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(artifactDestroyMock).toBeCalledWith(releaseId) expect(artifactDestroyMock).toHaveBeenCalledWith(releaseId)
assertOutputApplied() assertOutputApplied()
}) })
@@ -151,7 +153,7 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(artifactDestroyMock).not.toBeCalled() expect(artifactDestroyMock).not.toHaveBeenCalled()
assertOutputApplied() assertOutputApplied()
}) })
@@ -161,8 +163,8 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).not.toBeCalled() expect(createMock).not.toHaveBeenCalled()
expect(updateMock).not.toBeCalled() expect(updateMock).not.toHaveBeenCalled()
}) })
it("throws error when create fails", async () => { it("throws error when create fails", async () => {
@@ -176,7 +178,7 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -187,7 +189,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toHaveBeenCalled()
}) })
it("throws error when get fails", async () => { it("throws error when get fails", async () => {
@@ -209,9 +211,9 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(getMock).toBeCalledWith(tag) expect(getMock).toHaveBeenCalledWith(tag)
expect(updateMock).not.toBeCalled() expect(updateMock).not.toHaveBeenCalled()
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toHaveBeenCalled()
}) })
it("throws error when list has no data", async () => { it("throws error when list has no data", async () => {
@@ -234,9 +236,9 @@ describe("Action", () => {
expect(error).toEqual(Error("No releases found. Response: {}")) expect(error).toEqual(Error("No releases found. Response: {}"))
} }
expect(listMock).toBeCalled() expect(listMock).toHaveBeenCalled()
expect(createMock).not.toBeCalled() expect(createMock).not.toHaveBeenCalled()
expect(updateMock).not.toBeCalled() expect(updateMock).not.toHaveBeenCalled()
}) })
it("throws error when update fails", async () => { it("throws error when update fails", async () => {
@@ -251,10 +253,10 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(updateMock).toBeCalledWith( expect(updateMock).toHaveBeenCalledWith(
id, id,
tag, tag,
updateBody, generatedReleaseBody,
commit, commit,
discussionCategory, discussionCategory,
updateDraft, updateDraft,
@@ -262,7 +264,7 @@ describe("Action", () => {
updateName, updateName,
updatePrerelease updatePrerelease
) )
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toHaveBeenCalled()
}) })
it("throws error when upload fails", async () => { it("throws error when upload fails", async () => {
@@ -277,7 +279,7 @@ describe("Action", () => {
expect(error).toEqual(expectedError) expect(error).toEqual(expectedError)
} }
expect(createMock).toBeCalledWith( expect(createMock).toHaveBeenCalledWith(
tag, tag,
createBody, createBody,
commit, commit,
@@ -288,7 +290,7 @@ describe("Action", () => {
createName, createName,
createPrerelease createPrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
}) })
it("updates draft release", async () => { it("updates draft release", async () => {
@@ -304,7 +306,35 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(updateMock).toBeCalledWith( expect(updateMock).toHaveBeenCalledWith(
id,
tag,
generatedReleaseBody,
commit,
discussionCategory,
updateDraft,
makeLatest,
updateName,
updatePrerelease
)
expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied()
})
it("updates draft release with static body", async () => {
const action = createAction(true, true, false, false)
const error = { status: 404 }
getMock.mockRejectedValue(error)
listMock.mockResolvedValue({
data: [
{ id: 123, draft: false, tag_name: tag },
{ id: id, draft: true, tag_name: tag },
],
})
await action.perform()
expect(updateMock).toHaveBeenCalledWith(
id, id,
tag, tag,
updateBody, updateBody,
@@ -315,7 +345,7 @@ describe("Action", () => {
updateName, updateName,
updatePrerelease updatePrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
}) })
@@ -324,10 +354,10 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(updateMock).toBeCalledWith( expect(updateMock).toHaveBeenCalledWith(
id, id,
tag, tag,
updateBody, generatedReleaseBody,
commit, commit,
discussionCategory, discussionCategory,
updateDraft, updateDraft,
@@ -335,7 +365,7 @@ describe("Action", () => {
updateName, updateName,
updatePrerelease updatePrerelease
) )
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toHaveBeenCalled()
assertOutputApplied() assertOutputApplied()
}) })
@@ -344,10 +374,10 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(updateMock).toBeCalledWith( expect(updateMock).toHaveBeenCalledWith(
id, id,
tag, tag,
updateBody, generatedReleaseBody,
commit, commit,
discussionCategory, discussionCategory,
updateDraft, updateDraft,
@@ -355,21 +385,31 @@ describe("Action", () => {
updateName, updateName,
updatePrerelease updatePrerelease
) )
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toHaveBeenCalledWith(artifacts, releaseId, url)
assertOutputApplied() assertOutputApplied()
}) })
function assertOutputApplied() { function assertOutputApplied() {
expect(applyReleaseDataMock).toBeCalledWith({ id: releaseId, upload_url: url }) expect(applyReleaseDataMock).toHaveBeenCalledWith({
id: releaseId,
upload_url: url,
})
} }
function createAction(allowUpdates: boolean, hasArtifact: boolean, removeArtifacts: boolean = false): Action { function createAction(
allowUpdates: boolean,
hasArtifact: boolean,
removeArtifacts = false,
generateReleaseNotes = true
): Action {
let inputArtifact: Artifact[] let inputArtifact: Artifact[]
if (hasArtifact) { if (hasArtifact) {
inputArtifact = artifacts inputArtifact = artifacts
} else { } else {
inputArtifact = [] inputArtifact = []
} }
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = jest.fn<Releases, any>(() => {
return { return {
create: createMock, create: createMock,
@@ -379,6 +419,7 @@ describe("Action", () => {
listReleases: listMock, listReleases: listMock,
update: updateMock, update: updateMock,
uploadArtifact: jest.fn(), uploadArtifact: jest.fn(),
generateReleaseNotes: genReleaseNotesMock,
} }
}) })
@@ -388,6 +429,12 @@ describe("Action", () => {
upload_url: url, upload_url: url,
}, },
}) })
genReleaseNotesMock.mockResolvedValue({
data: {
body: generatedReleaseBody,
},
})
getMock.mockResolvedValue({ getMock.mockResolvedValue({
data: { data: {
id: id, id: id,
@@ -407,24 +454,24 @@ describe("Action", () => {
const MockInputs = jest.fn<Inputs, any>(() => { const MockInputs = jest.fn<Inputs, any>(() => {
return { return {
allowUpdates: allowUpdates, allowUpdates,
artifactErrorsFailBuild: true, artifactErrorsFailBuild: true,
artifacts: inputArtifact, artifacts: inputArtifact,
createdDraft: createDraft, createdDraft: createDraft,
createdReleaseBody: createBody, createdReleaseBody: createBody,
createdReleaseName: createName, createdReleaseName: createName,
commit: commit, commit,
discussionCategory: discussionCategory, discussionCategory,
generateReleaseNotes: true, generateReleaseNotes,
makeLatest: makeLatest, makeLatest: makeLatest,
owner: "owner", owner: "owner",
createdPrerelease: createPrerelease, createdPrerelease: createPrerelease,
replacesArtifacts: replacesArtifacts, replacesArtifacts,
removeArtifacts: removeArtifacts, removeArtifacts,
repo: "repo", repo: "repo",
skipIfReleaseExists: false, skipIfReleaseExists: false,
tag: tag, tag,
token: token, token,
updatedDraft: updateDraft, updatedDraft: updateDraft,
updatedReleaseBody: updateBody, updatedReleaseBody: updateBody,
updatedReleaseName: updateName, updatedReleaseName: updateName,

View File

@@ -1,5 +1,5 @@
import { ActionSkipper, ReleaseActionSkipper } from "../src/ActionSkipper" import { ReleaseActionSkipper } from "../src/ActionSkipper"
import { Releases } from "../src/Releases" import type { Releases } from "../src/Releases"
describe("shouldSkip", () => { describe("shouldSkip", () => {
const getMock = jest.fn() const getMock = jest.fn()
@@ -13,6 +13,7 @@ describe("shouldSkip", () => {
listReleases: jest.fn(), listReleases: jest.fn(),
update: jest.fn(), update: jest.fn(),
uploadArtifact: jest.fn(), uploadArtifact: jest.fn(),
generateReleaseNotes: jest.fn(),
} }
}) })

View File

@@ -1,8 +1,5 @@
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 { GithubArtifactDestroyer } from "../src/ArtifactDestroyer"
import type { Releases } from "../src/Releases"
const releaseId = 100 const releaseId = 100
@@ -22,7 +19,7 @@ describe("ArtifactDestroyer", () => {
await destroyer.destroyArtifacts(releaseId) await destroyer.destroyArtifacts(releaseId)
expect(deleteMock).toBeCalledTimes(2) expect(deleteMock).toHaveBeenCalledTimes(2)
}) })
it("destroys nothing when no artifacts found", async () => { it("destroys nothing when no artifacts found", async () => {
@@ -31,7 +28,7 @@ describe("ArtifactDestroyer", () => {
await destroyer.destroyArtifacts(releaseId) await destroyer.destroyArtifacts(releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(0)
}) })
it("throws when delete call fails", async () => { it("throws when delete call fails", async () => {
@@ -57,6 +54,7 @@ describe("ArtifactDestroyer", () => {
listReleases: jest.fn(), listReleases: jest.fn(),
update: jest.fn(), update: jest.fn(),
uploadArtifact: jest.fn(), uploadArtifact: jest.fn(),
generateReleaseNotes: jest.fn(),
} }
}) })
return new GithubArtifactDestroyer(new MockReleases()) return new GithubArtifactDestroyer(new MockReleases())

View File

@@ -1,7 +1,7 @@
import { RequestError } from "@octokit/request-error"
import { Artifact } from "../src/Artifact" import { Artifact } from "../src/Artifact"
import { GithubArtifactUploader } from "../src/ArtifactUploader" import { GithubArtifactUploader } from "../src/ArtifactUploader"
import { Releases } from "../src/Releases" import type { 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 fakeReadStream = {}
@@ -39,11 +39,11 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(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 () => {
@@ -53,14 +53,14 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(5) expect(uploadMock).toHaveBeenCalledTimes(5)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(0)
}) })
it("replaces all artifacts", async () => { it("replaces all artifacts", async () => {
@@ -71,13 +71,13 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(2) expect(deleteMock).toHaveBeenCalledTimes(2)
expect(deleteMock).toBeCalledWith(1) expect(deleteMock).toHaveBeenCalledWith(1)
expect(deleteMock).toBeCalledWith(2) expect(deleteMock).toHaveBeenCalledWith(2)
}) })
it("replaces no artifacts when previous asset list empty", async () => { it("replaces no artifacts when previous asset list empty", async () => {
@@ -88,11 +88,11 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(0)
}) })
it("retry when upload failed with 5xx response", async () => { it("retry when upload failed with 5xx response", async () => {
@@ -102,13 +102,13 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(4) expect(uploadMock).toHaveBeenCalledTimes(4)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(0)
}) })
it("throws upload error when replacesExistingArtifacts is true", async () => { it("throws upload error when replacesExistingArtifacts is true", async () => {
@@ -146,14 +146,14 @@ describe("ArtifactUploader", () => {
await uploader.uploadArtifacts(artifacts, releaseId, url) await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2) expect(uploadMock).toHaveBeenCalledTimes(2)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art1", releaseId)
expect(uploadMock).toBeCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId) expect(uploadMock).toHaveBeenCalledWith(url, contentLength, "raw", fakeReadStream, "art2", releaseId)
expect(deleteMock).toBeCalledTimes(0) expect(deleteMock).toHaveBeenCalledTimes(0)
}) })
function createUploader(replaces: boolean, throws: boolean = false): GithubArtifactUploader { function createUploader(replaces: boolean, throws = false): GithubArtifactUploader {
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = jest.fn<Releases, any>(() => {
return { return {
create: jest.fn(), create: jest.fn(),
@@ -163,6 +163,7 @@ describe("ArtifactUploader", () => {
listReleases: jest.fn(), listReleases: jest.fn(),
update: jest.fn(), update: jest.fn(),
uploadArtifact: uploadMock, uploadArtifact: uploadMock,
generateReleaseNotes: jest.fn(),
} }
}) })
return new GithubArtifactUploader(new MockReleases(), replaces, throws) return new GithubArtifactUploader(new MockReleases(), replaces, throws)
@@ -193,7 +194,7 @@ describe("ArtifactUploader", () => {
listArtifactsMock.mockResolvedValue([]) listArtifactsMock.mockResolvedValue([])
} }
function mockUploadArtifact(status: number = 200, failures: number = 0) { function mockUploadArtifact(status = 200, failures = 0) {
const error = new RequestError(`HTTP ${status}`, status, { const error = new RequestError(`HTTP ${status}`, status, {
headers: {}, headers: {},
request: { method: "GET", url: "", headers: {} }, request: { method: "GET", url: "", headers: {} },

1544
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,18 +1,18 @@
import * as core from "@actions/core" import * as core from "@actions/core"
import { Inputs } from "./Inputs" import type { ActionSkipper } from "./ActionSkipper"
import { import type { ArtifactDestroyer } from "./ArtifactDestroyer"
import type { ArtifactUploader } from "./ArtifactUploader"
import { GithubError } from "./GithubError"
import type { Inputs } from "./Inputs"
import type { Outputs } from "./Outputs"
import { ReleaseValidator } from "./ReleaseValidator"
import type {
CreateOrUpdateReleaseResponse, CreateOrUpdateReleaseResponse,
CreateReleaseResponse, CreateReleaseResponse,
ReleaseByTagResponse, ReleaseByTagResponse,
Releases, Releases,
UpdateReleaseResponse, UpdateReleaseResponse,
} from "./Releases" } 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 { export class Action {
private inputs: Inputs private inputs: Inputs
@@ -91,10 +91,17 @@ export class Action {
} }
private async updateRelease(id: number): Promise<UpdateReleaseResponse> { private async updateRelease(id: number): Promise<UpdateReleaseResponse> {
let releaseBody = this.inputs.updatedReleaseBody
if (this.inputs.generateReleaseNotes) {
const response = await this.releases.generateReleaseNotes(this.inputs.tag)
releaseBody = response.data.body
}
return await this.releases.update( return await this.releases.update(
id, id,
this.inputs.tag, this.inputs.tag,
this.inputs.updatedReleaseBody, releaseBody,
this.inputs.commit, this.inputs.commit,
this.inputs.discussionCategory, this.inputs.discussionCategory,
this.inputs.updatedDraft, this.inputs.updatedDraft,

View File

@@ -1,7 +1,7 @@
import { GitHub } from "@actions/github/lib/utils" import type { GitHub } from "@actions/github/lib/utils"
import { OctokitResponse } from "@octokit/types" import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods"
import { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods" import type { OctokitResponse } from "@octokit/types"
import { Inputs } from "./Inputs" import type { Inputs } from "./Inputs"
export type CreateReleaseResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"] export type CreateReleaseResponse = RestEndpointMethodTypes["repos"]["createRelease"]["response"]
export type ReleaseByTagResponse = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"] export type ReleaseByTagResponse = RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"]
@@ -10,6 +10,7 @@ export type ListReleaseAssetsResponseData = RestEndpointMethodTypes["repos"]["li
export type UpdateReleaseResponse = RestEndpointMethodTypes["repos"]["updateRelease"]["response"] export type UpdateReleaseResponse = RestEndpointMethodTypes["repos"]["updateRelease"]["response"]
export type UploadArtifactResponse = RestEndpointMethodTypes["repos"]["uploadReleaseAsset"]["response"] export type UploadArtifactResponse = RestEndpointMethodTypes["repos"]["uploadReleaseAsset"]["response"]
export type CreateOrUpdateReleaseResponse = CreateReleaseResponse | UpdateReleaseResponse export type CreateOrUpdateReleaseResponse = CreateReleaseResponse | UpdateReleaseResponse
export type GenerateReleaseNotesResponse = RestEndpointMethodTypes["repos"]["generateReleaseNotes"]["response"]
export type ReleaseData = { export type ReleaseData = {
id: number id: number
@@ -34,6 +35,8 @@ export interface Releases {
getByTag(tag: string): Promise<ReleaseByTagResponse> getByTag(tag: string): Promise<ReleaseByTagResponse>
generateReleaseNotes(tag: string): Promise<GenerateReleaseNotesResponse>
listArtifactsForRelease(releaseId: number): Promise<ListReleaseAssetsResponseData> listArtifactsForRelease(releaseId: number): Promise<ListReleaseAssetsResponseData>
listReleases(): Promise<ListReleasesResponse> listReleases(): Promise<ListReleasesResponse>
@@ -104,6 +107,14 @@ export class GithubReleases implements Releases {
}) })
} }
async generateReleaseNotes(tag: string): Promise<GenerateReleaseNotesResponse> {
return this.git.rest.repos.generateReleaseNotes({
owner: this.inputs.owner,
repo: this.inputs.repo,
tag_name: tag,
})
}
async getByTag(tag: string): Promise<ReleaseByTagResponse> { async getByTag(tag: string): Promise<ReleaseByTagResponse> {
return this.git.rest.repos.getReleaseByTag({ return this.git.rest.repos.getReleaseByTag({
owner: this.inputs.owner, owner: this.inputs.owner,