12 Commits

Author SHA1 Message Date
Nick Cipollo
81af6e69fb Prepare 1.6.0 release
Some checks failed
PR Checks / check_pr (push) Has been cancelled
2020-03-02 22:24:25 -05:00
Nick Cipollo
d57d57cad2 Fixes #12 Artifacts will now be replaced 2020-03-02 22:20:41 -05:00
Nick Cipollo
767a5edcf4 Fix tests 2020-01-02 23:46:48 -05:00
Nick Cipollo
cffd02c48e Add artifact upload error handling 2020-01-02 23:31:20 -05:00
Nick Cipollo
04d64ce68e Fixes #8 Add support for draft release updating 2020-01-02 22:56:16 -05:00
Nick Cipollo
c8e9e33d90 Update jest 2020-01-02 17:59:03 -05:00
Nick Cipollo
8f1cb7790e Merge pull request #9 from ncipollo/dependabot/npm_and_yarn/handlebars-4.5.3
Bump handlebars from 4.1.2 to 4.5.3
2020-01-02 17:56:05 -05:00
dependabot[bot]
40267624b8 Bump handlebars from 4.1.2 to 4.5.3
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-29 20:48:31 +00:00
Nick Cipollo
cb3417d207 Add prerelease 2019-12-13 16:05:44 -05:00
Nick Cipollo
5ce722314c Fix tests 2019-12-13 15:52:52 -05:00
Nick Cipollo
734853d8c8 Clean up logging and fix error handling 2019-12-13 15:40:34 -05:00
Nick Cipollo
b25a3c63b3 Fixes #7 Check if release exists before creating 2019-12-13 14:27:57 -05:00
21 changed files with 586 additions and 191 deletions

View File

@@ -12,6 +12,8 @@ This action will create a github release and optionally upload an artifact to it
- **commit**: An optional commit reference. This will be used to create the tag if it does not exist. - **commit**: An optional commit reference. This will be used to create the tag if it does not exist.
- **draft**: Optionally marks this release as a draft release. Set to `true` to enable. - **draft**: Optionally marks this release as a draft release. Set to `true` to enable.
- **name**: An optional name for the release. If this is omitted the tag will be used. - **name**: An optional name for the release. If this is omitted the tag will be used.
- **prerelease**: Optionally marks this release as prerelease. Set to true to enable.
- **replacesArtifacts**: Indicates if existing release artifacts should be replaced. Defaults to true.
- **tag**: An optional tag for the release. If this is omitted the git ref will be used (if it is a tag). - **tag**: An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).
- **token**: (**Required**) The Github token. Typically this will be `${{ secrets.GITHUB_TOKEN }}`. - **token**: (**Required**) The Github token. Typically this will be `${{ secrets.GITHUB_TOKEN }}`.

View File

@@ -5,7 +5,10 @@ import { Releases } from "../src/Releases";
import { ArtifactUploader } from "../src/ArtifactUploader"; import { ArtifactUploader } from "../src/ArtifactUploader";
const createMock = jest.fn() const createMock = jest.fn()
const deleteMock = jest.fn()
const getMock = jest.fn() const getMock = jest.fn()
const listArtifactsMock = jest.fn()
const listMock = jest.fn()
const updateMock = jest.fn() const updateMock = jest.fn()
const uploadMock = jest.fn() const uploadMock = jest.fn()
@@ -19,6 +22,9 @@ const commit = 'commit'
const draft = true const draft = true
const id = 100 const id = 100
const name = 'name' const name = 'name'
const prerelease = true
const releaseId = 101
const replacesArtifacts = true
const tag = 'tag' const tag = 'tag'
const token = 'token' const token = 'token'
const url = 'http://api.example.com' const url = 'http://api.example.com'
@@ -27,6 +33,7 @@ describe("Action", () => {
beforeEach(() => { beforeEach(() => {
createMock.mockClear() createMock.mockClear()
getMock.mockClear() getMock.mockClear()
listMock.mockClear()
updateMock.mockClear() updateMock.mockClear()
uploadMock.mockClear() uploadMock.mockClear()
}) })
@@ -36,17 +43,45 @@ describe("Action", () => {
await action.perform() await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
}) })
it('creates release if no release exists to update', async () => {
const action = createAction(true, true)
const error = { status: 404 }
getMock.mockRejectedValue(error)
await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
})
it('creates release if no draft releases', async () => {
const action = createAction(true, true)
const error = { status: 404 }
getMock.mockRejectedValue(error)
listMock.mockResolvedValue({
data: [
{ id: id, draft: false, tag_name: tag }
]
})
await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
})
it('creates release then uploads artifact', async () => { it('creates release then uploads artifact', async () => {
const action = createAction(false, true) const action = createAction(false, true)
await action.perform() await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, url) expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
}) })
it('throws error when create fails', async () => { it('throws error when create fails', async () => {
@@ -60,12 +95,12 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
}) })
it('throws error when get fails', async () => { it('throws error when get fails', async () => {
const action = createAction(true, false) const action = createAction(true, true)
const error = { const error = {
errors: [ errors: [
{ {
@@ -83,23 +118,17 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(getMock).toBeCalledWith(tag)
expect(updateMock).not.toBeCalled()
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
}) })
it('throws error when update fails', async () => { it('throws error when update fails', async () => {
const action = createAction(true, false) const action = createAction(true, true)
const error = {
errors: [
{
code: 'already_exists'
}
]
}
createMock.mockRejectedValue(error)
updateMock.mockRejectedValue("error") updateMock.mockRejectedValue("error")
expect.hasAssertions() expect.hasAssertions()
try { try {
await action.perform() await action.perform()
@@ -107,9 +136,8 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(updateMock).toBeCalledWith(id, tag, body, commit, draft, name, prerelease)
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
}) })
it('throws error when upload fails', async () => { it('throws error when upload fails', async () => {
@@ -123,45 +151,45 @@ describe("Action", () => {
expect(error).toEqual("error") expect(error).toEqual("error")
} }
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(createMock).toBeCalledWith(tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, url) expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
})
it('updates draft release', async () => {
const action = createAction(true, true)
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).toBeCalledWith(id, tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
}) })
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) const action = createAction(true, false)
const error = {
errors: [
{
code: 'already_exists'
}
]
}
createMock.mockRejectedValue(error)
await action.perform() await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(updateMock).toBeCalledWith(id, tag, body, commit, draft, name, prerelease)
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
}) })
it('updates release then uploads artifact', async () => { it('updates release then uploads artifact', async () => {
const action = createAction(true, true) const action = createAction(true, true)
const error = {
errors: [
{
code: 'already_exists'
}
]
}
createMock.mockRejectedValue(error)
await action.perform() await action.perform()
expect(createMock).toBeCalledWith(tag, body, commit, draft, name) expect(updateMock).toBeCalledWith(id, tag, body, commit, draft, name, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, url) expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
}) })
@@ -175,14 +203,18 @@ describe("Action", () => {
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = jest.fn<Releases, any>(() => {
return { return {
create: createMock, create: createMock,
deleteArtifact: deleteMock,
getByTag: getMock, getByTag: getMock,
listArtifactsForRelease: listArtifactsMock,
listReleases: listMock,
update: updateMock, update: updateMock,
uploadArtifact: uploadMock uploadArtifact: jest.fn()
} }
}) })
createMock.mockResolvedValue({ createMock.mockResolvedValue({
data: { data: {
id: releaseId,
upload_url: url upload_url: url
} }
}) })
@@ -191,8 +223,12 @@ describe("Action", () => {
id: id id: id
} }
}) })
listMock.mockResolvedValue({
data: []
})
updateMock.mockResolvedValue({ updateMock.mockResolvedValue({
data: { data: {
id: releaseId,
upload_url: url upload_url: url
} }
}) })
@@ -206,6 +242,8 @@ describe("Action", () => {
commit: commit, commit: commit,
draft: draft, draft: draft,
name: name, name: name,
prerelease: prerelease,
replacesArtifacts: replacesArtifacts,
tag: tag, tag: tag,
token: token, token: token,
readArtifact: () => artifactData readArtifact: () => artifactData

View File

@@ -8,9 +8,13 @@ const artifacts = [
] ]
const fileContents = Buffer.from('artful facts', 'utf-8') const fileContents = Buffer.from('artful facts', 'utf-8')
const contentLength = 42 const contentLength = 42
const uploadMock = jest.fn() 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', () => { jest.mock('fs', () => {
return { return {
readFileSync: () => fileContents, readFileSync: () => fileContents,
@@ -19,27 +23,115 @@ jest.mock('fs', () => {
}) })
describe('ArtifactUploader', () => { describe('ArtifactUploader', () => {
it('uploads artifacts', () => { beforeEach(() => {
const uploader = createUploader() deleteMock.mockClear()
listArtifactsMock.mockClear()
uploadMock.mockClear()
})
uploader.uploadArtifacts(artifacts, url) it('replaces all artifacts', async () => {
mockDeleteSuccess()
mockListWithAssets()
const uploader = createUploader(true)
await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2) expect(uploadMock).toBeCalledTimes(2)
expect(uploadMock) expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art1') .toBeCalledWith(url, contentLength, 'raw', fileContents, 'art1')
expect(uploadMock) expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art2') .toBeCalledWith(url, contentLength, 'raw', fileContents, 'art2')
expect(deleteMock).toBeCalledTimes(2)
expect(deleteMock).toBeCalledWith(1)
expect(deleteMock).toBeCalledWith(2)
}) })
function createUploader(): GithubArtifactUploader { it('replaces no artifacts when previous asset list empty', async () => {
mockDeleteSuccess()
mockListWithoutAssets()
const uploader = createUploader(true)
await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2)
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art1')
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art2')
expect(deleteMock).toBeCalledTimes(0)
})
it('throws error from replace', async () => {
mockDeleteError()
mockListWithAssets()
const uploader = createUploader(true)
expect.hasAssertions()
try {
await uploader.uploadArtifacts(artifacts, releaseId, url)
} catch (error) {
expect(error).toEqual("error")
}
})
it('updates all artifacts, delete none', async () => {
mockDeleteError()
mockListWithAssets()
const uploader = createUploader(false)
await uploader.uploadArtifacts(artifacts, releaseId, url)
expect(uploadMock).toBeCalledTimes(2)
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art1')
expect(uploadMock)
.toBeCalledWith(url, contentLength, 'raw', fileContents, 'art2')
expect(deleteMock).toBeCalledTimes(0)
})
function createUploader(replaces: boolean): GithubArtifactUploader {
uploadMock.mockResolvedValue({})
const MockReleases = jest.fn<Releases, any>(() => { const MockReleases = jest.fn<Releases, any>(() => {
return { return {
getByTag: jest.fn(),
create: jest.fn(), create: jest.fn(),
deleteArtifact: deleteMock,
getByTag: jest.fn(),
listArtifactsForRelease: listArtifactsMock,
listReleases: jest.fn(),
update: jest.fn(), update: jest.fn(),
uploadArtifact: uploadMock uploadArtifact: uploadMock
} }
}) })
return new GithubArtifactUploader(new MockReleases()) return new GithubArtifactUploader(new MockReleases(), replaces)
}
function mockDeleteError(): any {
deleteMock.mockRejectedValue("error")
}
function mockDeleteSuccess(): any {
deleteMock.mockResolvedValue({})
}
function mockListWithAssets() {
listArtifactsMock.mockResolvedValue({
data: [
{
name: "art1",
id: 1
},
{
name: "art2",
id: 2
}
]
})
}
function mockListWithoutAssets() {
listArtifactsMock.mockResolvedValue({ data: [] })
} }
}); });

View File

@@ -14,15 +14,16 @@ describe('ErrorMessage', () => {
code: 'already_exists', code: 'already_exists',
resource: 'release' resource: 'release'
} }
] ],
status: 422
} }
it('does not have error', ()=> { it('does not have error', () => {
const errorMessage = new ErrorMessage(error) const errorMessage = new ErrorMessage(error)
expect(errorMessage.hasErrorWithCode('missing_field')).toBeFalsy() expect(errorMessage.hasErrorWithCode('missing_field')).toBeFalsy()
}) })
it('has error', ()=> { it('has error', () => {
const errorMessage = new ErrorMessage(error) const errorMessage = new ErrorMessage(error)
expect(errorMessage.hasErrorWithCode('missing')).toBeTruthy() expect(errorMessage.hasErrorWithCode('missing')).toBeTruthy()
}) })
@@ -41,22 +42,30 @@ describe('ErrorMessage', () => {
code: 'already_exists', code: 'already_exists',
resource: 'release' resource: 'release'
} }
] ],
status: 422
} }
const errorMessage = new ErrorMessage(error) const errorMessage = new ErrorMessage(error)
const expectedString = "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(errorMessage.toString()).toBe(expectedString) expect(errorMessage.toString()).toBe(expectedString)
}) })
it('generates message without errors', () => { it('generates message without errors', () => {
const error = { const error = {
message: 'something bad happened' message: 'something bad happened',
status: 422
} }
const errorMessage = new ErrorMessage(error) const errorMessage = new ErrorMessage(error)
expect(errorMessage.toString()).toBe('something bad happened') expect(errorMessage.toString()).toBe('Error 422: something bad happened')
})
it('provides error status', () => {
const error = { status: 404 }
const errorMessage = new ErrorMessage(error)
expect(errorMessage.status).toBe(404)
}) })
}) })

View File

@@ -133,6 +133,28 @@ describe('Inputs', () => {
}) })
}) })
describe('prerelase', () => {
it('returns false', () => {
expect(inputs.prerelease).toBe(false)
})
it('returns true', () => {
mockGetInput.mockReturnValue('true')
expect(inputs.prerelease).toBe(true)
})
})
describe('replacesArtifacts', () => {
it('returns false', () => {
expect(inputs.replacesArtifacts).toBe(false)
})
it('returns true', () => {
mockGetInput.mockReturnValue('true')
expect(inputs.replacesArtifacts).toBe(true)
})
})
describe('tag', () => { describe('tag', () => {
it('returns input tag', () => { it('returns input tag', () => {
mockGetInput.mockReturnValue('tag') mockGetInput.mockReturnValue('tag')

View File

@@ -29,6 +29,12 @@ inputs:
name: name:
description: 'An optional name for the release. If this is omitted the tag will be used.' description: 'An optional name for the release. If this is omitted the tag will be used.'
default: '' default: ''
prerelease:
description: "Optionally marks this release as prerelease. Set to true to enable."
default: ''
replacesArtifacts:
description: "Indicates if existing release artifacts should be replaced. Defaults to true."
default: 'true'
tag: tag:
description: 'An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).' description: 'An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).'
default: '' default: ''

View File

@@ -18,44 +18,71 @@ class Action {
} }
perform() { perform() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const uploadUrl = yield this.createOrUpdateRelease(); const releaseResponse = yield this.createOrUpdateRelease();
const releaseId = releaseResponse.id;
const uploadUrl = releaseResponse.upload_url;
const artifacts = this.inputs.artifacts; const artifacts = this.inputs.artifacts;
if (artifacts.length > 0) { if (artifacts.length > 0) {
yield this.uploader.uploadArtifacts(artifacts, uploadUrl); yield this.uploader.uploadArtifacts(artifacts, releaseId, uploadUrl);
} }
}); });
} }
createOrUpdateRelease() { createOrUpdateRelease() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { if (this.inputs.allowUpdates) {
try {
const getResponse = yield this.releases.getByTag(this.inputs.tag);
return yield this.updateRelease(getResponse.data.id);
}
catch (error) {
if (this.noPublishedRelease(error)) {
return yield this.updateDraftOrCreateRelease();
}
else {
throw error;
}
}
}
else {
return yield this.createRelease(); return yield this.createRelease();
} }
catch (error) { });
if (this.releaseAlreadyExisted(error) && this.inputs.allowUpdates) { }
return this.updateRelease(); updateRelease(id) {
} return __awaiter(this, void 0, void 0, function* () {
else { const response = yield this.releases.update(id, this.inputs.tag, this.inputs.body, this.inputs.commit, this.inputs.draft, this.inputs.name, this.inputs.prerelease);
throw error; return response.data;
} });
}
noPublishedRelease(error) {
const errorMessage = new ErrorMessage_1.ErrorMessage(error);
return errorMessage.status == 404;
}
updateDraftOrCreateRelease() {
return __awaiter(this, void 0, void 0, function* () {
const draftReleaseId = yield this.findMatchingDraftReleaseId();
if (draftReleaseId) {
return yield this.updateRelease(draftReleaseId);
} }
else {
return yield this.createRelease();
}
});
}
findMatchingDraftReleaseId() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const tag = this.inputs.tag;
const response = yield this.releases.listReleases();
const releases = response.data;
const draftRelease = releases.find(release => release.draft && release.tag_name == tag);
return (_a = draftRelease) === null || _a === void 0 ? void 0 : _a.id;
}); });
} }
createRelease() { createRelease() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const response = yield this.releases.create(this.inputs.tag, this.inputs.body, this.inputs.commit, this.inputs.draft, this.inputs.name); const response = yield this.releases.create(this.inputs.tag, this.inputs.body, this.inputs.commit, this.inputs.draft, this.inputs.name, this.inputs.prerelease);
return response.data.upload_url; return response.data;
});
}
releaseAlreadyExisted(error) {
const errorMessage = new ErrorMessage_1.ErrorMessage(error);
return errorMessage.hasErrorWithCode('already_exists');
}
updateRelease() {
return __awaiter(this, void 0, void 0, function* () {
const getResponse = yield this.releases.getByTag(this.inputs.tag);
const id = getResponse.data.id;
const response = yield this.releases.update(id, this.inputs.tag, this.inputs.body, this.inputs.commit, this.inputs.draft, this.inputs.name);
return response.data.upload_url;
}); });
} }
} }

View File

@@ -8,16 +8,52 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next()); step((generator = generator.apply(thisArg, _arguments || [])).next());
}); });
}; };
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(require("@actions/core"));
class GithubArtifactUploader { class GithubArtifactUploader {
constructor(releases) { constructor(releases, replacesExistingArtifacts) {
this.replacesExistingArtifacts = true;
this.releases = releases; this.releases = releases;
this.replacesExistingArtifacts = replacesExistingArtifacts;
} }
uploadArtifacts(artifacts, uploadUrl) { uploadArtifacts(artifacts, releaseId, uploadUrl) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
artifacts.forEach((artifact) => __awaiter(this, void 0, void 0, function* () { if (this.replacesExistingArtifacts) {
yield this.releases.uploadArtifact(uploadUrl, artifact.contentLength, artifact.contentType, artifact.readFile(), artifact.name); yield this.deleteUpdatedArtifacts(artifacts, releaseId);
})); }
for (const artifact of artifacts) {
try {
yield this.releases.uploadArtifact(uploadUrl, artifact.contentLength, artifact.contentType, artifact.readFile(), artifact.name);
}
catch (error) {
const message = `Failed to upload artifact ${artifact.name}. Does it already exist?`;
core.warning(message);
}
}
return Promise.resolve();
});
}
deleteUpdatedArtifacts(artifacts, releaseId) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.releases.listArtifactsForRelease(releaseId);
const releaseAssets = response.data;
const assetByName = new Map();
releaseAssets.forEach(asset => {
assetByName[asset.name] = asset;
});
for (const artifact of artifacts) {
const asset = assetByName[artifact.name];
if (asset) {
yield this.releases.deleteArtifact(asset.id);
}
}
}); });
} }
} }

View File

@@ -15,17 +15,21 @@ class ErrorMessage {
return []; return [];
} }
} }
get status() {
return this.error.status;
}
hasErrorWithCode(code) { hasErrorWithCode(code) {
return this.githubErrors.some((err) => err.code == code); return this.githubErrors.some((err) => err.code == code);
} }
toString() { toString() {
const message = this.error.message; const message = this.error.message;
const errors = this.githubErrors; const errors = this.githubErrors;
const status = this.status;
if (errors.length > 0) { if (errors.length > 0) {
return `${message}\nErrors:\n${this.errorBulletedList(errors)}`; return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`;
} }
else { else {
return message; return `Error ${status}: ${message}`;
} }
} }
errorBulletedList(errors) { errorBulletedList(errors) {

View File

@@ -58,6 +58,14 @@ class CoreInputs {
} }
return this.tag; return this.tag;
} }
get prerelease() {
const preRelease = core.getInput('prerelease');
return preRelease == 'true';
}
get replacesArtifacts() {
const replaces = core.getInput('replacesArtifacts');
return replaces == 'true';
}
get tag() { get tag() {
const tag = core.getInput('tag'); const tag = core.getInput('tag');
if (tag) { if (tag) {

View File

@@ -43,7 +43,7 @@ function createAction() {
const globber = new ArtifactGlobber_1.FileArtifactGlobber(); const globber = new ArtifactGlobber_1.FileArtifactGlobber();
const inputs = new Inputs_1.CoreInputs(globber, context); const inputs = new Inputs_1.CoreInputs(globber, context);
const releases = new Releases_1.GithubReleases(context, git); const releases = new Releases_1.GithubReleases(context, git);
const uploader = new ArtifactUploader_1.GithubArtifactUploader(releases); const uploader = new ArtifactUploader_1.GithubArtifactUploader(releases, inputs.replacesArtifacts);
return new Action_1.Action(inputs, releases, uploader); return new Action_1.Action(inputs, releases, uploader);
} }
run(); run();

View File

@@ -14,19 +14,46 @@ class GithubReleases {
this.context = context; this.context = context;
this.git = git; this.git = git;
} }
create(tag, body, commitHash, draft, name) { create(tag, body, commitHash, draft, name, prerelease) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.createRelease({ return this.git.repos.createRelease({
body: body, body: body,
name: name, name: name,
draft: draft, draft: draft,
owner: this.context.repo.owner, owner: this.context.repo.owner,
prerelease: prerelease,
repo: this.context.repo.repo, repo: this.context.repo.repo,
target_commitish: commitHash, target_commitish: commitHash,
tag_name: tag tag_name: tag
}); });
}); });
} }
deleteArtifact(assetId) {
return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.deleteReleaseAsset({
asset_id: assetId,
owner: this.context.repo.owner,
repo: this.context.repo.repo
});
});
}
listArtifactsForRelease(releaseId) {
return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.listAssetsForRelease({
owner: this.context.repo.owner,
release_id: releaseId,
repo: this.context.repo.repo
});
});
}
listReleases() {
return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.listReleases({
owner: this.context.repo.owner,
repo: this.context.repo.repo
});
});
}
getByTag(tag) { getByTag(tag) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.getReleaseByTag({ return this.git.repos.getReleaseByTag({
@@ -36,7 +63,7 @@ class GithubReleases {
}); });
}); });
} }
update(id, tag, body, commitHash, draft, name) { update(id, tag, body, commitHash, draft, name, prerelease) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
return this.git.repos.updateRelease({ return this.git.repos.updateRelease({
release_id: id, release_id: id,
@@ -44,6 +71,7 @@ class GithubReleases {
name: name, name: name,
draft: draft, draft: draft,
owner: this.context.repo.owner, owner: this.context.repo.owner,
prerelease: prerelease,
repo: this.context.repo.repo, repo: this.context.repo.repo,
target_commitish: commitHash, target_commitish: commitHash,
tag_name: tag tag_name: tag

31
node_modules/.yarn-integrity generated vendored
View File

@@ -11,14 +11,14 @@
"@actions/core@^1.0.0", "@actions/core@^1.0.0",
"@actions/github@^1.0.0", "@actions/github@^1.0.0",
"@types/glob@^7.1.1", "@types/glob@^7.1.1",
"@types/jest@^24.0.13", "@types/jest@^24.0.25",
"@types/node@^12.0.4", "@types/node@^12.0.4",
"add@^2.0.6", "add@^2.0.6",
"glob@^7.1.4", "glob@^7.1.4",
"global@^4.4.0", "global@^4.4.0",
"jest-circus@^24.7.1", "jest-circus@^24.7.1",
"jest@^24.8.0", "jest@^24.9.0",
"ts-jest@^24.0.2", "ts-jest@^24.2.0",
"typescript@^3.7.3" "typescript@^3.7.3"
], ],
"lockfileEntries": { "lockfileEntries": {
@@ -81,8 +81,7 @@
"@types/istanbul-lib-coverage@^2.0.0": "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff", "@types/istanbul-lib-coverage@^2.0.0": "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff",
"@types/istanbul-lib-report@*": "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c", "@types/istanbul-lib-report@*": "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c",
"@types/istanbul-reports@^1.1.1": "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a", "@types/istanbul-reports@^1.1.1": "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a",
"@types/jest-diff@*": "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89", "@types/jest@^24.0.25": "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.25.tgz#2aba377824ce040114aa906ad2cac2c85351360f",
"@types/jest@^24.0.13": "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.18.tgz#9c7858d450c59e2164a8a9df0905fc5091944498",
"@types/minimatch@*": "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d", "@types/minimatch@*": "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d",
"@types/node@*": "https://registry.yarnpkg.com/@types/node/-/node-12.7.3.tgz#27b3f40addaf2f580459fdb405222685542f907a", "@types/node@*": "https://registry.yarnpkg.com/@types/node/-/node-12.7.3.tgz#27b3f40addaf2f580459fdb405222685542f907a",
"@types/node@^12.0.4": "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44", "@types/node@^12.0.4": "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44",
@@ -161,7 +160,7 @@
"color-name@1.1.3": "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25", "color-name@1.1.3": "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25",
"combined-stream@^1.0.6": "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f", "combined-stream@^1.0.6": "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f",
"combined-stream@~1.0.6": "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f", "combined-stream@~1.0.6": "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f",
"commander@~2.20.0": "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422", "commander@~2.20.3": "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33",
"component-emitter@^1.2.1": "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0", "component-emitter@^1.2.1": "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0",
"concat-map@0.0.1": "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b", "concat-map@0.0.1": "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b",
"console-control-strings@^1.0.0": "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e", "console-control-strings@^1.0.0": "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e",
@@ -253,7 +252,7 @@
"graceful-fs@^4.1.15": "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02", "graceful-fs@^4.1.15": "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02",
"graceful-fs@^4.1.2": "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02", "graceful-fs@^4.1.2": "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02",
"growly@^1.3.0": "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081", "growly@^1.3.0": "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081",
"handlebars@^4.1.2": "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67", "handlebars@^4.1.2": "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482",
"har-schema@^2.0.0": "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92", "har-schema@^2.0.0": "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92",
"har-validator@~5.1.0": "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080", "har-validator@~5.1.0": "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080",
"has-flag@^3.0.0": "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd", "has-flag@^3.0.0": "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd",
@@ -325,6 +324,7 @@
"jest-circus@^24.7.1": "https://registry.yarnpkg.com/jest-circus/-/jest-circus-24.9.0.tgz#8a557683636807d537507eac02ba64c95b686485", "jest-circus@^24.7.1": "https://registry.yarnpkg.com/jest-circus/-/jest-circus-24.9.0.tgz#8a557683636807d537507eac02ba64c95b686485",
"jest-cli@^24.9.0": "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af", "jest-cli@^24.9.0": "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af",
"jest-config@^24.9.0": "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5", "jest-config@^24.9.0": "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5",
"jest-diff@^24.3.0": "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da",
"jest-diff@^24.9.0": "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da", "jest-diff@^24.9.0": "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da",
"jest-docblock@^24.3.0": "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2", "jest-docblock@^24.3.0": "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2",
"jest-each@^24.9.0": "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05", "jest-each@^24.9.0": "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05",
@@ -351,7 +351,7 @@
"jest-watcher@^24.9.0": "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b", "jest-watcher@^24.9.0": "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b",
"jest-worker@^24.6.0": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5", "jest-worker@^24.6.0": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5",
"jest-worker@^24.9.0": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5", "jest-worker@^24.9.0": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5",
"jest@^24.8.0": "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171", "jest@^24.9.0": "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171",
"js-tokens@^3.0.0 || ^4.0.0": "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499", "js-tokens@^3.0.0 || ^4.0.0": "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499",
"js-tokens@^4.0.0": "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499", "js-tokens@^4.0.0": "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499",
"jsbn@~0.1.0": "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513", "jsbn@~0.1.0": "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513",
@@ -378,6 +378,7 @@
"load-json-file@^4.0.0": "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b", "load-json-file@^4.0.0": "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b",
"locate-path@^3.0.0": "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e", "locate-path@^3.0.0": "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e",
"lodash.get@^4.4.2": "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99", "lodash.get@^4.4.2": "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99",
"lodash.memoize@4.x": "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe",
"lodash.set@^4.3.2": "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23", "lodash.set@^4.3.2": "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23",
"lodash.sortby@^4.7.0": "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438", "lodash.sortby@^4.7.0": "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438",
"lodash.uniq@^4.5.0": "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773", "lodash.uniq@^4.5.0": "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773",
@@ -593,13 +594,13 @@
"tough-cookie@~2.4.3": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781", "tough-cookie@~2.4.3": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781",
"tr46@^1.0.1": "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09", "tr46@^1.0.1": "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09",
"trim-right@^1.0.1": "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003", "trim-right@^1.0.1": "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003",
"ts-jest@^24.0.2": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.0.2.tgz#8dde6cece97c31c03e80e474c749753ffd27194d", "ts-jest@^24.2.0": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.2.0.tgz#7abca28c2b4b0a1fdd715cd667d65d047ea4e768",
"tunnel-agent@^0.6.0": "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd", "tunnel-agent@^0.6.0": "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd",
"tweetnacl@^0.14.3": "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64", "tweetnacl@^0.14.3": "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64",
"tweetnacl@~0.14.0": "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64", "tweetnacl@~0.14.0": "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64",
"type-check@~0.3.2": "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72", "type-check@~0.3.2": "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72",
"typescript@^3.7.3": "https://registry.yarnpkg.com/typescript/-/typescript-3.7.3.tgz#b36840668a16458a7025b9eabfad11b66ab85c69", "typescript@^3.7.3": "https://registry.yarnpkg.com/typescript/-/typescript-3.7.3.tgz#b36840668a16458a7025b9eabfad11b66ab85c69",
"uglify-js@^3.1.4": "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5", "uglify-js@^3.1.4": "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a",
"union-value@^1.0.0": "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847", "union-value@^1.0.0": "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847",
"universal-user-agent@^2.0.3": "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.1.0.tgz#5abfbcc036a1ba490cb941f8fd68c46d3669e8e4", "universal-user-agent@^2.0.3": "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.1.0.tgz#5abfbcc036a1ba490cb941f8fd68c46d3669e8e4",
"universal-user-agent@^3.0.0": "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-3.0.0.tgz#4cc88d68097bffd7ac42e3b7c903e7481424b4b9", "universal-user-agent@^3.0.0": "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-3.0.0.tgz#4cc88d68097bffd7ac42e3b7c903e7481424b4b9",
@@ -643,5 +644,13 @@
"yargs@^13.3.0": "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" "yargs@^13.3.0": "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
}, },
"files": [], "files": [],
"artifacts": {} "artifacts": {
"fsevents@1.2.9": [
"lib",
"lib/binding",
"lib/binding/Release",
"lib/binding/Release/node-v72-darwin-x64",
"lib/binding/Release/node-v72-darwin-x64/fse.node"
]
}
} }

View File

@@ -32,10 +32,10 @@
"global": "^4.4.0" "global": "^4.4.0"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.13", "@types/jest": "^24.0.25",
"jest": "^24.8.0", "jest": "^24.9.0",
"jest-circus": "^24.7.1", "jest-circus": "^24.7.1",
"ts-jest": "^24.0.2", "ts-jest": "^24.2.0",
"typescript": "^3.7.3" "typescript": "^3.7.3"
} }
} }

View File

@@ -1,5 +1,6 @@
import { Inputs } from "./Inputs"; import { Inputs } from "./Inputs";
import { Releases } from "./Releases"; import { Releases } from "./Releases";
import { ReposCreateReleaseResponse } from "@octokit/rest";
import { ArtifactUploader } from "./ArtifactUploader"; import { ArtifactUploader } from "./ArtifactUploader";
import { ErrorMessage } from "./ErrorMessage"; import { ErrorMessage } from "./ErrorMessage";
@@ -15,56 +16,80 @@ export class Action {
} }
async perform() { async perform() {
const uploadUrl = await this.createOrUpdateRelease() const releaseResponse = await this.createOrUpdateRelease();
const releaseId = releaseResponse.id
const uploadUrl = releaseResponse.upload_url
const artifacts = this.inputs.artifacts const artifacts = this.inputs.artifacts
if (artifacts.length > 0) { if (artifacts.length > 0) {
await this.uploader.uploadArtifacts(artifacts, uploadUrl) await this.uploader.uploadArtifacts(artifacts, releaseId, uploadUrl)
} }
} }
private async createOrUpdateRelease(): Promise<string> { private async createOrUpdateRelease(): Promise<ReposCreateReleaseResponse> {
try { if (this.inputs.allowUpdates) {
return await this.createRelease() try {
} catch (error) { const getResponse = await this.releases.getByTag(this.inputs.tag)
if (this.releaseAlreadyExisted(error) && this.inputs.allowUpdates) { return await this.updateRelease(getResponse.data.id)
return this.updateRelease() } catch (error) {
} else { if (this.noPublishedRelease(error)) {
throw error return await this.updateDraftOrCreateRelease()
} else {
throw error
}
} }
} else {
return await this.createRelease()
} }
} }
private async createRelease(): Promise<string> { private async updateRelease(id: number): Promise<ReposCreateReleaseResponse> {
const response = await this.releases.create(
this.inputs.tag,
this.inputs.body,
this.inputs.commit,
this.inputs.draft,
this.inputs.name
)
return response.data.upload_url
}
private releaseAlreadyExisted(error: any): boolean {
const errorMessage = new ErrorMessage(error)
return errorMessage.hasErrorWithCode('already_exists')
}
private async updateRelease(): Promise<string> {
const getResponse = await this.releases.getByTag(this.inputs.tag)
const id = getResponse.data.id
const response = await this.releases.update( const response = await this.releases.update(
id, id,
this.inputs.tag, this.inputs.tag,
this.inputs.body, this.inputs.body,
this.inputs.commit, this.inputs.commit,
this.inputs.draft, this.inputs.draft,
this.inputs.name this.inputs.name,
this.inputs.prerelease
) )
return response.data.upload_url return response.data
}
private noPublishedRelease(error: any): boolean {
const errorMessage = new ErrorMessage(error)
return errorMessage.status == 404
}
private async updateDraftOrCreateRelease(): Promise<ReposCreateReleaseResponse> {
const draftReleaseId = await this.findMatchingDraftReleaseId()
if (draftReleaseId) {
return await this.updateRelease(draftReleaseId)
} else {
return await this.createRelease()
}
}
private async findMatchingDraftReleaseId(): Promise<number | undefined> {
const tag = this.inputs.tag
const response = await this.releases.listReleases()
const releases = response.data
const draftRelease = releases.find(release => release.draft && release.tag_name == tag)
return draftRelease?.id
}
private async createRelease(): Promise<ReposCreateReleaseResponse> {
const response = await this.releases.create(
this.inputs.tag,
this.inputs.body,
this.inputs.commit,
this.inputs.draft,
this.inputs.name,
this.inputs.prerelease
)
return response.data
} }
} }

View File

@@ -1,24 +1,56 @@
import * as core from '@actions/core';
import { Artifact } from "./Artifact"; import { Artifact } from "./Artifact";
import { Releases } from "./Releases"; import { Releases } from "./Releases";
import { ReposListAssetsForReleaseResponseItem } from "@octokit/rest";
import { ErrorMessage } from './ErrorMessage';
export interface ArtifactUploader { export interface ArtifactUploader {
uploadArtifacts(artifacts: Artifact[], uploadUrl: string): Promise<void> uploadArtifacts(artifacts: Artifact[], releaseId: number, uploadUrl: string): Promise<void>
} }
export class GithubArtifactUploader implements ArtifactUploader { export class GithubArtifactUploader implements ArtifactUploader {
private releases: Releases private releases: Releases
private replacesExistingArtifacts: boolean = true
constructor(releases: Releases) { constructor(releases: Releases, replacesExistingArtifacts: boolean) {
this.releases = releases this.releases = releases
this.replacesExistingArtifacts = replacesExistingArtifacts
} }
async uploadArtifacts(artifacts: Artifact[], uploadUrl: string) { async uploadArtifacts(artifacts: Artifact[],
artifacts.forEach(async artifact => { releaseId: number,
await this.releases.uploadArtifact(uploadUrl, uploadUrl: string): Promise<void> {
artifact.contentLength, if(this.replacesExistingArtifacts) {
artifact.contentType, await this.deleteUpdatedArtifacts(artifacts, releaseId)
artifact.readFile(), }
artifact.name)
for (const artifact of artifacts) {
try {
await this.releases.uploadArtifact(uploadUrl,
artifact.contentLength,
artifact.contentType,
artifact.readFile(),
artifact.name)
} catch (error) {
const message = `Failed to upload artifact ${artifact.name}. Does it already exist?`
core.warning(message)
}
}
return Promise.resolve()
}
async deleteUpdatedArtifacts(artifacts: Artifact[], releaseId: number) {
const response = await this.releases.listArtifactsForRelease(releaseId)
const releaseAssets = response.data
const assetByName = new Map<string, ReposListAssetsForReleaseResponseItem>()
releaseAssets.forEach(asset => {
assetByName[asset.name] = asset
}); });
for (const artifact of artifacts) {
const asset = assetByName[artifact.name]
if (asset) {
await this.releases.deleteArtifact(asset.id)
}
}
} }
} }

View File

@@ -18,6 +18,10 @@ export class ErrorMessage {
} }
} }
get status():number {
return this.error.status
}
hasErrorWithCode(code: String): boolean { hasErrorWithCode(code: String): boolean {
return this.githubErrors.some((err) => err.code == code) return this.githubErrors.some((err) => err.code == code)
} }
@@ -25,10 +29,11 @@ export class ErrorMessage {
toString(): string { toString(): string {
const message = this.error.message const message = this.error.message
const errors = this.githubErrors const errors = this.githubErrors
const status = this.status
if (errors.length > 0) { if (errors.length > 0) {
return `${message}\nErrors:\n${this.errorBulletedList(errors)}` return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`
} else { } else {
return message return `Error ${status}: ${message}`
} }
} }

View File

@@ -11,6 +11,8 @@ export interface Inputs {
readonly commit: string readonly commit: string
readonly draft: boolean readonly draft: boolean
readonly name: string readonly name: string
readonly prerelease: boolean
readonly replacesArtifacts: boolean
readonly tag: string readonly tag: string
readonly token: string readonly token: string
} }
@@ -77,6 +79,16 @@ export class CoreInputs implements Inputs {
return this.tag return this.tag
} }
get prerelease(): boolean {
const preRelease = core.getInput('prerelease')
return preRelease == 'true'
}
get replacesArtifacts(): boolean {
const replaces = core.getInput('replacesArtifacts')
return replaces == 'true'
}
get tag(): string { get tag(): string {
const tag = core.getInput('tag') const tag = core.getInput('tag')
if (tag) { if (tag) {

View File

@@ -25,7 +25,7 @@ function createAction(): Action {
const inputs = new CoreInputs(globber, context) const inputs = new CoreInputs(globber, context)
const releases = new GithubReleases(context, git) const releases = new GithubReleases(context, git)
const uploader = new GithubArtifactUploader(releases) const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts)
return new Action(inputs, releases, uploader) return new Action(inputs, releases, uploader)
} }

View File

@@ -1,6 +1,6 @@
import { Context } from "@actions/github/lib/context"; import { Context } from "@actions/github/lib/context";
import { GitHub } from "@actions/github"; import { GitHub } from "@actions/github";
import { AnyResponse, Response, ReposCreateReleaseResponse, ReposGetReleaseByTagResponse } from "@octokit/rest"; import { AnyResponse, Response, ReposDeleteReleaseAssetResponse, ReposListAssetsForReleaseResponse, ReposCreateReleaseResponse, ReposGetReleaseByTagResponse, ReposListReleasesResponse } from "@octokit/rest";
export interface Releases { export interface Releases {
create( create(
@@ -8,18 +8,26 @@ export interface Releases {
body?: string, body?: string,
commitHash?: string, commitHash?: string,
draft?: boolean, draft?: boolean,
name?: string name?: string,
prerelease?: boolean
): Promise<Response<ReposCreateReleaseResponse>> ): Promise<Response<ReposCreateReleaseResponse>>
deleteArtifact(assetId: number): Promise<Response<ReposDeleteReleaseAssetResponse>>
getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>> getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>>
listArtifactsForRelease(releaseId: number): Promise<Response<ReposListAssetsForReleaseResponse>>
listReleases(): Promise<Response<ReposListReleasesResponse>>
update( update(
id: number, id: number,
tag: string, tag: string,
body?: string, body?: string,
commitHash?: string, commitHash?: string,
draft?: boolean, draft?: boolean,
name?: string name?: string,
prerelease?: boolean
): Promise<Response<ReposCreateReleaseResponse>> ): Promise<Response<ReposCreateReleaseResponse>>
uploadArtifact( uploadArtifact(
@@ -45,19 +53,48 @@ export class GithubReleases implements Releases {
body?: string, body?: string,
commitHash?: string, commitHash?: string,
draft?: boolean, draft?: boolean,
name?: string name?: string,
prerelease?: boolean
): Promise<Response<ReposCreateReleaseResponse>> { ): Promise<Response<ReposCreateReleaseResponse>> {
return this.git.repos.createRelease({ return this.git.repos.createRelease({
body: body, body: body,
name: name, name: name,
draft: draft, draft: draft,
owner: this.context.repo.owner, owner: this.context.repo.owner,
prerelease: prerelease,
repo: this.context.repo.repo, repo: this.context.repo.repo,
target_commitish: commitHash, target_commitish: commitHash,
tag_name: tag tag_name: tag
}) })
} }
async deleteArtifact(
assetId: number
): Promise<Response<ReposDeleteReleaseAssetResponse>> {
return this.git.repos.deleteReleaseAsset({
asset_id: assetId,
owner: this.context.repo.owner,
repo: this.context.repo.repo
})
}
async listArtifactsForRelease(
releaseId: number
): Promise<Response<ReposListAssetsForReleaseResponse>> {
return this.git.repos.listAssetsForRelease({
owner: this.context.repo.owner,
release_id: releaseId,
repo: this.context.repo.repo
})
}
async listReleases(): Promise<Response<ReposListReleasesResponse>> {
return this.git.repos.listReleases({
owner: this.context.repo.owner,
repo: this.context.repo.repo
})
}
async getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>> { async getByTag(tag: string): Promise<Response<ReposGetReleaseByTagResponse>> {
return this.git.repos.getReleaseByTag({ return this.git.repos.getReleaseByTag({
owner: this.context.repo.owner, owner: this.context.repo.owner,
@@ -72,7 +109,8 @@ export class GithubReleases implements Releases {
body?: string, body?: string,
commitHash?: string, commitHash?: string,
draft?: boolean, draft?: boolean,
name?: string name?: string,
prerelease?: boolean
): Promise<Response<ReposCreateReleaseResponse>> { ): Promise<Response<ReposCreateReleaseResponse>> {
return this.git.repos.updateRelease({ return this.git.repos.updateRelease({
release_id: id, release_id: id,
@@ -80,6 +118,7 @@ export class GithubReleases implements Releases {
name: name, name: name,
draft: draft, draft: draft,
owner: this.context.repo.owner, owner: this.context.repo.owner,
prerelease: prerelease,
repo: this.context.repo.repo, repo: this.context.repo.repo,
target_commitish: commitHash, target_commitish: commitHash,
tag_name: tag tag_name: tag

View File

@@ -425,17 +425,12 @@
"@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*" "@types/istanbul-lib-report" "*"
"@types/jest-diff@*": "@types/jest@^24.0.25":
version "20.0.1" version "24.0.25"
resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.25.tgz#2aba377824ce040114aa906ad2cac2c85351360f"
integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== integrity sha512-hnP1WpjN4KbGEK4dLayul6lgtys6FPz0UfxMeMQCv0M+sTnzN3ConfiO72jHgLxl119guHgI8gLqDOrRLsyp2g==
"@types/jest@^24.0.13":
version "24.0.18"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.18.tgz#9c7858d450c59e2164a8a9df0905fc5091944498"
integrity sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==
dependencies: dependencies:
"@types/jest-diff" "*" jest-diff "^24.3.0"
"@types/minimatch@*": "@types/minimatch@*":
version "3.0.3" version "3.0.3"
@@ -887,10 +882,10 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@~2.20.0: commander@~2.20.3:
version "2.20.0" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
component-emitter@^1.2.1: component-emitter@^1.2.1:
version "1.3.0" version "1.3.0"
@@ -1416,9 +1411,9 @@ growly@^1.3.0:
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
handlebars@^4.1.2: handlebars@^4.1.2:
version "4.1.2" version "4.5.3"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
dependencies: dependencies:
neo-async "^2.6.0" neo-async "^2.6.0"
optimist "^0.6.1" optimist "^0.6.1"
@@ -1872,7 +1867,7 @@ jest-config@^24.9.0:
pretty-format "^24.9.0" pretty-format "^24.9.0"
realpath-native "^1.1.0" realpath-native "^1.1.0"
jest-diff@^24.9.0: jest-diff@^24.3.0, jest-diff@^24.9.0:
version "24.9.0" version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da"
integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==
@@ -2167,7 +2162,7 @@ jest-worker@^24.6.0, jest-worker@^24.9.0:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^6.1.0" supports-color "^6.1.0"
jest@^24.8.0: jest@^24.9.0:
version "24.9.0" version "24.9.0"
resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171"
integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==
@@ -2329,6 +2324,11 @@ lodash.get@^4.4.2:
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash.memoize@4.x:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.set@^4.3.2: lodash.set@^4.3.2:
version "4.3.2" version "4.3.2"
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
@@ -3525,15 +3525,16 @@ trim-right@^1.0.1:
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
ts-jest@^24.0.2: ts-jest@^24.2.0:
version "24.0.2" version "24.2.0"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.0.2.tgz#8dde6cece97c31c03e80e474c749753ffd27194d" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.2.0.tgz#7abca28c2b4b0a1fdd715cd667d65d047ea4e768"
integrity sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw== integrity sha512-Yc+HLyldlIC9iIK8xEN7tV960Or56N49MDP7hubCZUeI7EbIOTsas6rXCMB4kQjLACJ7eDOF4xWEO5qumpKsag==
dependencies: dependencies:
bs-logger "0.x" bs-logger "0.x"
buffer-from "1.x" buffer-from "1.x"
fast-json-stable-stringify "2.x" fast-json-stable-stringify "2.x"
json5 "2.x" json5 "2.x"
lodash.memoize "4.x"
make-error "1.x" make-error "1.x"
mkdirp "0.x" mkdirp "0.x"
resolve "1.x" resolve "1.x"
@@ -3565,11 +3566,11 @@ typescript@^3.7.3:
integrity sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw== integrity sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==
uglify-js@^3.1.4: uglify-js@^3.1.4:
version "3.6.0" version "3.7.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
dependencies: dependencies:
commander "~2.20.0" commander "~2.20.3"
source-map "~0.6.1" source-map "~0.6.1"
union-value@^1.0.0: union-value@^1.0.0: