Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d95f7f9bad |
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: "PR Checks"
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
|
|
||||||
- name: "yarn install"
|
|
||||||
run: yarn install
|
|
||||||
|
|
||||||
- name: "yarn build"
|
|
||||||
run: yarn build
|
|
||||||
|
|
||||||
- name: "check for uncommitted changes"
|
|
||||||
# Ensure no changes, but ignore node_modules dir since dev/fresh ci deps installed.
|
|
||||||
run: |
|
|
||||||
git diff --exit-code --stat -- . ':!node_modules' \
|
|
||||||
|| (echo "##[error] found changed files after build. please 'yarn build && npm run format'" \
|
|
||||||
"and check in all changes" \
|
|
||||||
&& exit 1)
|
|
||||||
25
.github/workflows/checkin.yml
vendored
Normal file
25
.github/workflows/checkin.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: "PR Checks"
|
||||||
|
on: [pull_request, push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: "yarn install"
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: "yarn build"
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: "yarn test"
|
||||||
|
run: yarn test
|
||||||
|
|
||||||
|
- name: "check for uncommitted changes"
|
||||||
|
# Ensure no changes, but ignore node_modules dir since dev/fresh ci deps installed.
|
||||||
|
run: |
|
||||||
|
git diff --exit-code --stat -- . ':!node_modules' \
|
||||||
|
|| (echo "##[error] found changed files after build. please 'yarn build && npm run format'" \
|
||||||
|
"and check in all changes" \
|
||||||
|
&& exit 1)
|
||||||
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
@@ -1,14 +0,0 @@
|
|||||||
name: "Test"
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
|
|
||||||
- name: "yarn install"
|
|
||||||
run: yarn install
|
|
||||||
|
|
||||||
- name: "yarn test"
|
|
||||||
run: yarn test
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,4 @@
|
|||||||
# node_modules/
|
#node_modules/
|
||||||
__tests__/runner/*
|
__tests__/runner/*
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/webstorm
|
# Created by https://www.gitignore.io/api/webstorm
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ This action will create a github release and optionally upload an artifact to it
|
|||||||
|
|
||||||
## Action Inputs
|
## Action Inputs
|
||||||
- **allowUpdates**: An optional flag which indicates if we should update a release if it already exists. Defaults to false.
|
- **allowUpdates**: An optional flag which indicates if we should update a release if it already exists. Defaults to false.
|
||||||
- **artifactErrorsFailBuild**: An optional flag which indicates if artifact read or upload errors should fail the build.
|
|
||||||
- **artifact**: An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs).
|
- **artifact**: An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs).
|
||||||
- **artifacts**: An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs).
|
- **artifacts**: An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs).
|
||||||
- **artifactContentType**: The content type of the artifact. Defaults to raw.
|
- **artifactContentType**: The content type of the artifact. Defaults to raw.
|
||||||
- **body**: An optional body for the release.
|
- **body**: An optional body for the release.
|
||||||
- **bodyFile**: An optional body file for the release. This should be the path to the file.
|
- **bodyFile**: An optional body file for the release. This should be the path to the file.
|
||||||
- **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.
|
||||||
- **discussionCategory**: When provided this will generate a discussion of the specified category. The category must exist otherwise this will cause the action to fail. This isn't used with draft releases.
|
|
||||||
- **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.
|
||||||
- **omitBody**: Indicates if the release body should be omitted.
|
- **omitBody**: Indicates if the release body should be omitted.
|
||||||
@@ -25,11 +23,6 @@ This action will create a github release and optionally upload an artifact to it
|
|||||||
- **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 }}`.
|
||||||
|
|
||||||
## Action Outputs
|
|
||||||
- **id**: The identifier of the created release.
|
|
||||||
- **html_url**: The HTML URL of the release.
|
|
||||||
- **upload_url**: The URL for uploading assets to the release.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
This example will create a release when tag is pushed:
|
This example will create a release when tag is pushed:
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import {Artifact} from "../src/Artifact";
|
|||||||
import {Inputs} from "../src/Inputs";
|
import {Inputs} from "../src/Inputs";
|
||||||
import {Releases} from "../src/Releases";
|
import {Releases} from "../src/Releases";
|
||||||
import {ArtifactUploader} from "../src/ArtifactUploader";
|
import {ArtifactUploader} from "../src/ArtifactUploader";
|
||||||
import {Outputs} from "../src/Outputs";
|
|
||||||
|
|
||||||
const applyReleaseDataMock = jest.fn()
|
|
||||||
const createMock = jest.fn()
|
const createMock = jest.fn()
|
||||||
const deleteMock = jest.fn()
|
const deleteMock = jest.fn()
|
||||||
const getMock = jest.fn()
|
const getMock = jest.fn()
|
||||||
@@ -22,7 +20,6 @@ const artifacts = [
|
|||||||
const createBody = 'createBody'
|
const createBody = 'createBody'
|
||||||
const createName = 'createName'
|
const createName = 'createName'
|
||||||
const commit = 'commit'
|
const commit = 'commit'
|
||||||
const discussionCategory = 'discussionCategory'
|
|
||||||
const draft = true
|
const draft = true
|
||||||
const id = 100
|
const id = 100
|
||||||
const prerelease = true
|
const prerelease = true
|
||||||
@@ -48,9 +45,8 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).not.toBeCalled()
|
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 () => {
|
||||||
@@ -60,9 +56,8 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
assertOutputApplied()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('creates release if no draft releases', async () => {
|
it('creates release if no draft releases', async () => {
|
||||||
@@ -77,9 +72,8 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
assertOutputApplied()
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,9 +82,8 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
assertOutputApplied()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws error when create fails', async () => {
|
it('throws error when create fails', async () => {
|
||||||
@@ -104,7 +97,7 @@ describe("Action", () => {
|
|||||||
expect(error).toEqual("error")
|
expect(error).toEqual("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).not.toBeCalled()
|
expect(uploadMock).not.toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -145,32 +138,22 @@ describe("Action", () => {
|
|||||||
expect(error).toEqual("error")
|
expect(error).toEqual("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(updateMock).toBeCalledWith(
|
expect(updateMock).toBeCalledWith(id, tag, updateBody, commit, draft, updateName, prerelease)
|
||||||
id,
|
|
||||||
tag,
|
|
||||||
updateBody,
|
|
||||||
commit,
|
|
||||||
discussionCategory,
|
|
||||||
draft,
|
|
||||||
updateName,
|
|
||||||
prerelease
|
|
||||||
)
|
|
||||||
expect(uploadMock).not.toBeCalled()
|
expect(uploadMock).not.toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws error when upload fails', async () => {
|
it('throws error when upload fails', async () => {
|
||||||
const action = createAction(false, true)
|
const action = createAction(false, true)
|
||||||
const expectedError = {status: 404}
|
uploadMock.mockRejectedValue("error")
|
||||||
uploadMock.mockRejectedValue(expectedError)
|
|
||||||
|
|
||||||
expect.hasAssertions()
|
expect.hasAssertions()
|
||||||
try {
|
try {
|
||||||
await action.perform()
|
await action.perform()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error).toEqual(expectedError)
|
expect(error).toEqual("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
|
expect(createMock).toBeCalledWith(tag, createBody, commit, draft, createName, prerelease)
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -187,18 +170,9 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(updateMock).toBeCalledWith(
|
expect(updateMock).toBeCalledWith(id, tag, updateBody, commit, draft, updateName, prerelease)
|
||||||
id,
|
|
||||||
tag,
|
|
||||||
updateBody,
|
|
||||||
commit,
|
|
||||||
discussionCategory,
|
|
||||||
draft,
|
|
||||||
updateName,
|
|
||||||
prerelease
|
|
||||||
)
|
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
assertOutputApplied()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('updates release but does not upload if no artifact', async () => {
|
it('updates release but does not upload if no artifact', async () => {
|
||||||
@@ -206,18 +180,9 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(updateMock).toBeCalledWith(
|
expect(updateMock).toBeCalledWith(id, tag, updateBody, commit, draft, updateName, prerelease)
|
||||||
id,
|
|
||||||
tag,
|
|
||||||
updateBody,
|
|
||||||
commit,
|
|
||||||
discussionCategory,
|
|
||||||
draft,
|
|
||||||
updateName,
|
|
||||||
prerelease
|
|
||||||
)
|
|
||||||
expect(uploadMock).not.toBeCalled()
|
expect(uploadMock).not.toBeCalled()
|
||||||
assertOutputApplied()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('updates release then uploads artifact', async () => {
|
it('updates release then uploads artifact', async () => {
|
||||||
@@ -225,23 +190,10 @@ describe("Action", () => {
|
|||||||
|
|
||||||
await action.perform()
|
await action.perform()
|
||||||
|
|
||||||
expect(updateMock).toBeCalledWith(
|
expect(updateMock).toBeCalledWith(id, tag, updateBody, commit, draft, updateName, prerelease)
|
||||||
id,
|
|
||||||
tag,
|
|
||||||
updateBody,
|
|
||||||
commit,
|
|
||||||
discussionCategory,
|
|
||||||
draft,
|
|
||||||
updateName,
|
|
||||||
prerelease
|
|
||||||
)
|
|
||||||
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
|
||||||
assertOutputApplied()
|
|
||||||
})
|
|
||||||
|
|
||||||
function assertOutputApplied() {
|
})
|
||||||
expect(applyReleaseDataMock).toBeCalledWith({id: releaseId, upload_url: url})
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAction(allowUpdates: boolean, hasArtifact: boolean): Action {
|
function createAction(allowUpdates: boolean, hasArtifact: boolean): Action {
|
||||||
let inputArtifact: Artifact[]
|
let inputArtifact: Artifact[]
|
||||||
@@ -287,12 +239,10 @@ describe("Action", () => {
|
|||||||
const MockInputs = jest.fn<Inputs, any>(() => {
|
const MockInputs = jest.fn<Inputs, any>(() => {
|
||||||
return {
|
return {
|
||||||
allowUpdates: allowUpdates,
|
allowUpdates: allowUpdates,
|
||||||
artifactErrorsFailBuild: true,
|
|
||||||
artifacts: inputArtifact,
|
artifacts: inputArtifact,
|
||||||
createdReleaseBody: createBody,
|
createdReleaseBody: createBody,
|
||||||
createdReleaseName: createName,
|
createdReleaseName: createName,
|
||||||
commit: commit,
|
commit: commit,
|
||||||
discussionCategory: discussionCategory,
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
owner: "owner",
|
owner: "owner",
|
||||||
prerelease: prerelease,
|
prerelease: prerelease,
|
||||||
@@ -304,11 +254,6 @@ describe("Action", () => {
|
|||||||
updatedReleaseName: updateName
|
updatedReleaseName: updateName
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const MockOutputs = jest.fn<Outputs, any>(() => {
|
|
||||||
return {
|
|
||||||
applyReleaseData: applyReleaseDataMock
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const MockUploader = jest.fn<ArtifactUploader, any>(() => {
|
const MockUploader = jest.fn<ArtifactUploader, any>(() => {
|
||||||
return {
|
return {
|
||||||
uploadArtifacts: uploadMock
|
uploadArtifacts: uploadMock
|
||||||
@@ -316,10 +261,9 @@ describe("Action", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const inputs = new MockInputs()
|
const inputs = new MockInputs()
|
||||||
const outputs = new MockOutputs()
|
|
||||||
const releases = new MockReleases()
|
const releases = new MockReleases()
|
||||||
const uploader = new MockUploader()
|
const uploader = new MockUploader()
|
||||||
|
|
||||||
return new Action(inputs, outputs, releases, uploader)
|
return new Action(inputs, releases, uploader)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
const warnMock = jest.fn()
|
const warnMock = jest.fn()
|
||||||
|
|
||||||
import {FileArtifactGlobber} from "../src/ArtifactGlobber"
|
import { FileArtifactGlobber } from "../src/ArtifactGlobber"
|
||||||
import {Globber} from "../src/Globber";
|
import { Globber } from "../src/Globber";
|
||||||
import {Artifact} from "../src/Artifact";
|
import { Artifact } from "../src/Artifact";
|
||||||
import untildify = require("untildify");
|
import untildify = require("untildify");
|
||||||
|
|
||||||
const contentType = "raw"
|
const contentType = "raw"
|
||||||
@@ -13,18 +13,6 @@ jest.mock('@actions/core', () => {
|
|||||||
return {warning: warnMock};
|
return {warning: warnMock};
|
||||||
})
|
})
|
||||||
|
|
||||||
jest.mock('fs', () => {
|
|
||||||
return {
|
|
||||||
statSync: () => {
|
|
||||||
return {
|
|
||||||
isDirectory(): boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("ArtifactGlobber", () => {
|
describe("ArtifactGlobber", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
globMock.mockClear()
|
globMock.mockClear()
|
||||||
@@ -36,19 +24,19 @@ describe("ArtifactGlobber", () => {
|
|||||||
const expectedArtifacts =
|
const expectedArtifacts =
|
||||||
globResults.map((path) => new Artifact(path, contentType))
|
globResults.map((path) => new Artifact(path, contentType))
|
||||||
|
|
||||||
expect(globber.globArtifactString('~/path', 'raw', false))
|
expect(globber.globArtifactString('~/path', 'raw'))
|
||||||
.toEqual(expectedArtifacts)
|
.toEqual(expectedArtifacts)
|
||||||
expect(globMock).toBeCalledWith(untildify('~/path'))
|
expect(globMock).toBeCalledWith(untildify('~/path'))
|
||||||
expect(warnMock).not.toBeCalled()
|
expect(warnMock).not.toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("globs simple path", () => {
|
it("globs simple path", () => {
|
||||||
const globber = createArtifactGlobber()
|
const globber = createArtifactGlobber()
|
||||||
|
|
||||||
const expectedArtifacts =
|
const expectedArtifacts =
|
||||||
globResults.map((path) => new Artifact(path, contentType))
|
globResults.map((path) => new Artifact(path, contentType))
|
||||||
|
|
||||||
expect(globber.globArtifactString('path', 'raw', false))
|
expect(globber.globArtifactString('path', 'raw'))
|
||||||
.toEqual(expectedArtifacts)
|
.toEqual(expectedArtifacts)
|
||||||
expect(globMock).toBeCalledWith('path')
|
expect(globMock).toBeCalledWith('path')
|
||||||
expect(warnMock).not.toBeCalled()
|
expect(warnMock).not.toBeCalled()
|
||||||
@@ -62,28 +50,24 @@ describe("ArtifactGlobber", () => {
|
|||||||
.concat(globResults)
|
.concat(globResults)
|
||||||
.map((path) => new Artifact(path, contentType))
|
.map((path) => new Artifact(path, contentType))
|
||||||
|
|
||||||
expect(globber.globArtifactString('path1,path2', 'raw', false))
|
expect(globber.globArtifactString('path1,path2', 'raw'))
|
||||||
.toEqual(expectedArtifacts)
|
.toEqual(expectedArtifacts)
|
||||||
expect(globMock).toBeCalledWith('path1')
|
expect(globMock).toBeCalledWith('path1')
|
||||||
expect(globMock).toBeCalledWith('path2')
|
expect(globMock).toBeCalledWith('path2')
|
||||||
expect(warnMock).not.toBeCalled()
|
expect(warnMock).not.toBeCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("warns when no glob results are produced and empty results shouldn't throw", () => {
|
it("warns when no glob results are produced", () => {
|
||||||
const globber = createArtifactGlobber([])
|
const globber = createArtifactGlobber([])
|
||||||
|
|
||||||
expect(globber.globArtifactString('path', 'raw', false))
|
const expectedArtifacts =
|
||||||
|
globResults.map((path) => new Artifact(path, contentType))
|
||||||
|
|
||||||
|
expect(globber.globArtifactString('path', 'raw'))
|
||||||
.toEqual([])
|
.toEqual([])
|
||||||
expect(warnMock).toBeCalled()
|
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)
|
|
||||||
}).toThrow()
|
|
||||||
})
|
|
||||||
|
|
||||||
function createArtifactGlobber(results: string[] = globResults): FileArtifactGlobber {
|
function createArtifactGlobber(results: string[] = globResults): FileArtifactGlobber {
|
||||||
const MockGlobber = jest.fn<Globber, any>(() => {
|
const MockGlobber = jest.fn<Globber, any>(() => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
const directoryMock = jest.fn()
|
|
||||||
const warnMock = jest.fn()
|
|
||||||
|
|
||||||
import {ArtifactPathValidator} from "../src/ArtifactPathValidator";
|
|
||||||
|
|
||||||
const pattern = 'pattern'
|
|
||||||
|
|
||||||
jest.mock('@actions/core', () => {
|
|
||||||
return {warning: warnMock};
|
|
||||||
})
|
|
||||||
|
|
||||||
jest.mock('fs', () => {
|
|
||||||
return {
|
|
||||||
statSync: () => {
|
|
||||||
return {isDirectory: directoryMock}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("ArtifactPathValidator", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
warnMock.mockClear()
|
|
||||||
directoryMock.mockClear()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("warns and filters out path which points to a directory", () => {
|
|
||||||
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'])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("warns when no glob results are produced and empty results shouldn't throw", () => {
|
|
||||||
const validator = new ArtifactPathValidator(false, [], pattern)
|
|
||||||
const result = validator.validate()
|
|
||||||
expect(warnMock).toBeCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("throws when no glob results are produced and empty results shouild throw", () => {
|
|
||||||
const validator = new ArtifactPathValidator(true, [], pattern)
|
|
||||||
expect(() => {
|
|
||||||
validator.validate()
|
|
||||||
}).toThrow()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("throws when path points to directory", () => {
|
|
||||||
const paths = ['path1', 'path2']
|
|
||||||
directoryMock.mockReturnValueOnce(true).mockReturnValueOnce(false)
|
|
||||||
|
|
||||||
const validator = new ArtifactPathValidator(true, paths, pattern)
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
validator.validate()
|
|
||||||
}).toThrow()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
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 { Releases } from "../src/Releases";
|
||||||
import {RequestError} from '@octokit/request-error'
|
import { RequestError } from '@octokit/request-error'
|
||||||
|
|
||||||
const artifacts = [
|
const artifacts = [
|
||||||
new Artifact('a/art1'),
|
new Artifact('a/art1'),
|
||||||
@@ -19,9 +19,7 @@ const uploadMock = jest.fn()
|
|||||||
jest.mock('fs', () => {
|
jest.mock('fs', () => {
|
||||||
return {
|
return {
|
||||||
readFileSync: () => fileContents,
|
readFileSync: () => fileContents,
|
||||||
statSync: () => {
|
statSync: () => { return { size: contentLength } }
|
||||||
return {size: contentLength}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -126,19 +124,6 @@ describe('ArtifactUploader', () => {
|
|||||||
expect(deleteMock).toBeCalledTimes(0)
|
expect(deleteMock).toBeCalledTimes(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws upload error when replacesExistingArtifacts is true', async () => {
|
|
||||||
mockListWithoutAssets()
|
|
||||||
mockUploadError()
|
|
||||||
const uploader = createUploader(true, true)
|
|
||||||
|
|
||||||
expect.hasAssertions()
|
|
||||||
try {
|
|
||||||
await uploader.uploadArtifacts(artifacts, releaseId, url)
|
|
||||||
} catch (error) {
|
|
||||||
expect(error).toEqual(Error("Failed to upload artifact art1. error."))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('throws error from replace', async () => {
|
it('throws error from replace', async () => {
|
||||||
mockDeleteError()
|
mockDeleteError()
|
||||||
mockListWithAssets()
|
mockListWithAssets()
|
||||||
@@ -170,7 +155,7 @@ describe('ArtifactUploader', () => {
|
|||||||
expect(deleteMock).toBeCalledTimes(0)
|
expect(deleteMock).toBeCalledTimes(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
function createUploader(replaces: boolean, throws: boolean = false): GithubArtifactUploader {
|
function createUploader(replaces: boolean): GithubArtifactUploader {
|
||||||
const MockReleases = jest.fn<Releases, any>(() => {
|
const MockReleases = jest.fn<Releases, any>(() => {
|
||||||
return {
|
return {
|
||||||
create: jest.fn(),
|
create: jest.fn(),
|
||||||
@@ -182,7 +167,7 @@ describe('ArtifactUploader', () => {
|
|||||||
uploadArtifact: uploadMock
|
uploadArtifact: uploadMock
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return new GithubArtifactUploader(new MockReleases(), replaces, throws)
|
return new GithubArtifactUploader(new MockReleases(), replaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockDeleteError(): any {
|
function mockDeleteError(): any {
|
||||||
@@ -194,37 +179,29 @@ describe('ArtifactUploader', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mockListWithAssets() {
|
function mockListWithAssets() {
|
||||||
listArtifactsMock.mockResolvedValue([
|
listArtifactsMock.mockResolvedValue({
|
||||||
{
|
data: [
|
||||||
name: "art1",
|
{
|
||||||
id: 1
|
name: "art1",
|
||||||
},
|
id: 1
|
||||||
{
|
},
|
||||||
name: "art2",
|
{
|
||||||
id: 2
|
name: "art2",
|
||||||
}
|
id: 2
|
||||||
])
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockListWithoutAssets() {
|
function mockListWithoutAssets() {
|
||||||
listArtifactsMock.mockResolvedValue([])
|
listArtifactsMock.mockResolvedValue({ data: [] })
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockUploadArtifact(status: number = 200, failures: number = 0) {
|
function mockUploadArtifact(status: number = 200, failures: number = 0) {
|
||||||
const error = new RequestError(`HTTP ${status}`, status, {
|
const error = new RequestError(`HTTP ${status}`, status, { headers: {}, request: { method: 'GET', url: '', headers: {} } })
|
||||||
headers: {},
|
|
||||||
request: {method: 'GET', url: '', headers: {}}
|
|
||||||
})
|
|
||||||
for (let index = 0; index < failures; index++) {
|
for (let index = 0; index < failures; index++) {
|
||||||
uploadMock.mockRejectedValueOnce(error)
|
uploadMock.mockRejectedValueOnce(error)
|
||||||
}
|
}
|
||||||
uploadMock.mockResolvedValue({})
|
uploadMock.mockResolvedValue({})
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockUploadError() {
|
|
||||||
uploadMock.mockRejectedValue({
|
|
||||||
message: "error",
|
|
||||||
status: 502
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
70
__tests__/ErrorMessage.test.ts
Normal file
70
__tests__/ErrorMessage.test.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { ErrorMessage } from "../src/ErrorMessage"
|
||||||
|
|
||||||
|
describe('ErrorMessage', () => {
|
||||||
|
|
||||||
|
describe('has error with code', () => {
|
||||||
|
const error = {
|
||||||
|
message: 'something bad happened',
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
code: 'missing',
|
||||||
|
resource: 'release'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'already_exists',
|
||||||
|
resource: 'release'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
|
||||||
|
it('does not have error', () => {
|
||||||
|
const errorMessage = new ErrorMessage(error)
|
||||||
|
expect(errorMessage.hasErrorWithCode('missing_field')).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has error', () => {
|
||||||
|
const errorMessage = new ErrorMessage(error)
|
||||||
|
expect(errorMessage.hasErrorWithCode('missing')).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates message with errors', () => {
|
||||||
|
const error = {
|
||||||
|
message: 'something bad happened',
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
code: 'missing',
|
||||||
|
resource: 'release'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'already_exists',
|
||||||
|
resource: 'release'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorMessage = new ErrorMessage(error)
|
||||||
|
|
||||||
|
const expectedString = "Error 422: something bad happened\nErrors:\n- release does not exist.\n- release already exists."
|
||||||
|
expect(errorMessage.toString()).toBe(expectedString)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates message without errors', () => {
|
||||||
|
const error = {
|
||||||
|
message: 'something bad happened',
|
||||||
|
status: 422
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorMessage = new ErrorMessage(error)
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,70 +1,99 @@
|
|||||||
import { GithubError } from "../src/GithubError"
|
import { GithubError } from "../src/GithubError"
|
||||||
|
|
||||||
describe('ErrorMessage', () => {
|
describe('GithubError', () => {
|
||||||
|
|
||||||
describe('has error with code', () => {
|
it('provides error code', () => {
|
||||||
const error = {
|
const error = {
|
||||||
message: 'something bad happened',
|
code: "missing"
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
code: 'missing',
|
|
||||||
resource: 'release'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'already_exists',
|
|
||||||
resource: 'release'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
status: 422
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it('does not have error', () => {
|
const githubError = new GithubError(error)
|
||||||
|
|
||||||
|
expect(githubError.code).toBe('missing')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates missing resource error message', () => {
|
||||||
|
const resource = "release"
|
||||||
|
const error = {
|
||||||
|
code: "missing",
|
||||||
|
resource: resource
|
||||||
|
}
|
||||||
|
|
||||||
|
const githubError = new GithubError(error)
|
||||||
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe(`${resource} does not exist.`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates missing field error message', () => {
|
||||||
|
const resource = "release"
|
||||||
|
const field = "body"
|
||||||
|
const error = {
|
||||||
|
code: "missing_field",
|
||||||
|
field: field,
|
||||||
|
resource: resource
|
||||||
|
}
|
||||||
|
|
||||||
|
const githubError = new GithubError(error)
|
||||||
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe(`The ${field} field on ${resource} is missing.`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates invalid field error message', () => {
|
||||||
|
const resource = "release"
|
||||||
|
const field = "body"
|
||||||
|
const error = {
|
||||||
|
code: "invalid",
|
||||||
|
field: field,
|
||||||
|
resource: resource
|
||||||
|
}
|
||||||
|
|
||||||
|
const githubError = new GithubError(error)
|
||||||
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe(`The ${field} field on ${resource} is an invalid format.`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('generates resource already exists error message', () => {
|
||||||
|
const resource = "release"
|
||||||
|
const field = "body"
|
||||||
|
const error = {
|
||||||
|
code: "already_exists",
|
||||||
|
resource: resource
|
||||||
|
}
|
||||||
|
|
||||||
|
const githubError = new GithubError(error)
|
||||||
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe(`${resource} already exists.`)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('generates custom error message', () => {
|
||||||
|
it('with documentation url', () => {
|
||||||
|
const url = "https://api.example.com"
|
||||||
|
const error = {
|
||||||
|
code: "custom",
|
||||||
|
message: "foo",
|
||||||
|
documentation_url: url
|
||||||
|
}
|
||||||
|
|
||||||
const githubError = new GithubError(error)
|
const githubError = new GithubError(error)
|
||||||
expect(githubError.hasErrorWithCode('missing_field')).toBeFalsy()
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe(`foo\nPlease see ${url}.`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has error', () => {
|
it('without documentation url', () => {
|
||||||
|
const error = {
|
||||||
|
code: "custom",
|
||||||
|
message: "foo"
|
||||||
|
}
|
||||||
|
|
||||||
const githubError = new GithubError(error)
|
const githubError = new GithubError(error)
|
||||||
expect(githubError.hasErrorWithCode('missing')).toBeTruthy()
|
const message = githubError.toString()
|
||||||
|
|
||||||
|
expect(message).toBe('foo')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
it('generates message with errors', () => {
|
|
||||||
const error = {
|
|
||||||
message: 'something bad happened',
|
|
||||||
errors: [
|
|
||||||
{
|
|
||||||
code: 'missing',
|
|
||||||
resource: 'release'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'already_exists',
|
|
||||||
resource: 'release'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
status: 422
|
|
||||||
}
|
|
||||||
|
|
||||||
const githubError = new GithubError(error)
|
|
||||||
|
|
||||||
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', () => {
|
|
||||||
const error = {
|
|
||||||
message: 'something bad happened',
|
|
||||||
status: 422
|
|
||||||
}
|
|
||||||
|
|
||||||
const githubError = new GithubError(error)
|
|
||||||
|
|
||||||
expect(githubError.toString()).toBe('Error 422: something bad happened')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('provides error status', () => {
|
|
||||||
const error = { status: 404 }
|
|
||||||
const githubError = new GithubError(error)
|
|
||||||
expect(githubError.status).toBe(404)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
import { GithubErrorDetail } from "../src/GithubErrorDetail"
|
|
||||||
|
|
||||||
describe('GithubErrorDetail', () => {
|
|
||||||
|
|
||||||
it('provides error code', () => {
|
|
||||||
const error = {
|
|
||||||
code: "missing"
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
|
|
||||||
expect(detail.code).toBe('missing')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('generates missing resource error message', () => {
|
|
||||||
const resource = "release"
|
|
||||||
const error = {
|
|
||||||
code: "missing",
|
|
||||||
resource: resource
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe(`${resource} does not exist.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('generates missing field error message', () => {
|
|
||||||
const resource = "release"
|
|
||||||
const field = "body"
|
|
||||||
const error = {
|
|
||||||
code: "missing_field",
|
|
||||||
field: field,
|
|
||||||
resource: resource
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe(`The ${field} field on ${resource} is missing.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('generates invalid field error message', () => {
|
|
||||||
const resource = "release"
|
|
||||||
const field = "body"
|
|
||||||
const error = {
|
|
||||||
code: "invalid",
|
|
||||||
field: field,
|
|
||||||
resource: resource
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe(`The ${field} field on ${resource} is an invalid format.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('generates resource already exists error message', () => {
|
|
||||||
const resource = "release"
|
|
||||||
const error = {
|
|
||||||
code: "already_exists",
|
|
||||||
resource: resource
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe(`${resource} already exists.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('generates custom error message', () => {
|
|
||||||
it('with documentation url', () => {
|
|
||||||
const url = "https://api.example.com"
|
|
||||||
const error = {
|
|
||||||
code: "custom",
|
|
||||||
message: "foo",
|
|
||||||
documentation_url: url
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe(`foo\nPlease see ${url}.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('without documentation url', () => {
|
|
||||||
const error = {
|
|
||||||
code: "custom",
|
|
||||||
message: "foo"
|
|
||||||
}
|
|
||||||
|
|
||||||
const detail = new GithubErrorDetail(error)
|
|
||||||
const message = detail.toString()
|
|
||||||
|
|
||||||
expect(message).toBe('foo')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -59,28 +59,7 @@ describe('Inputs', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('artifactErrorsFailBuild', () => {
|
|
||||||
it('returns false', () => {
|
|
||||||
expect(inputs.artifactErrorsFailBuild).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns true', () => {
|
|
||||||
mockGetInput.mockReturnValue('true')
|
|
||||||
expect(inputs.artifactErrorsFailBuild).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('artifacts', () => {
|
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)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns empty artifacts', () => {
|
it('returns empty artifacts', () => {
|
||||||
mockGetInput.mockReturnValueOnce('')
|
mockGetInput.mockReturnValueOnce('')
|
||||||
.mockReturnValueOnce('')
|
.mockReturnValueOnce('')
|
||||||
@@ -92,32 +71,28 @@ describe('Inputs', () => {
|
|||||||
it('returns input.artifacts', () => {
|
it('returns input.artifacts', () => {
|
||||||
mockGetInput.mockReturnValueOnce('art1')
|
mockGetInput.mockReturnValueOnce('art1')
|
||||||
.mockReturnValueOnce('contentType')
|
.mockReturnValueOnce('contentType')
|
||||||
.mockReturnValueOnce('false')
|
|
||||||
|
|
||||||
expect(inputs.artifacts).toEqual(artifacts)
|
expect(inputs.artifacts).toEqual(artifacts)
|
||||||
expect(mockGlob).toBeCalledTimes(1)
|
expect(mockGlob).toBeCalledTimes(1)
|
||||||
expect(mockGlob).toBeCalledWith('art1', 'contentType', false)
|
expect(mockGlob).toBeCalledWith('art1', 'contentType')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns input.artifacts with default contentType', () => {
|
it('returns input.artifacts with default contentType', () => {
|
||||||
mockGetInput.mockReturnValueOnce('art1')
|
mockGetInput.mockReturnValueOnce('art1')
|
||||||
.mockReturnValueOnce('raw')
|
|
||||||
.mockReturnValueOnce('false')
|
|
||||||
|
|
||||||
expect(inputs.artifacts).toEqual(artifacts)
|
expect(inputs.artifacts).toEqual(artifacts)
|
||||||
expect(mockGlob).toBeCalledTimes(1)
|
expect(mockGlob).toBeCalledTimes(1)
|
||||||
expect(mockGlob).toBeCalledWith('art1', 'raw', false)
|
expect(mockGlob).toBeCalledWith('art1', 'raw')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns input.artifact', () => {
|
it('returns input.artifact', () => {
|
||||||
mockGetInput.mockReturnValueOnce('')
|
mockGetInput.mockReturnValueOnce('')
|
||||||
.mockReturnValueOnce('art2')
|
.mockReturnValueOnce('art2')
|
||||||
.mockReturnValueOnce('contentType')
|
.mockReturnValueOnce('contentType')
|
||||||
.mockReturnValueOnce('false')
|
|
||||||
|
|
||||||
expect(inputs.artifacts).toEqual(artifacts)
|
expect(inputs.artifacts).toEqual(artifacts)
|
||||||
expect(mockGlob).toBeCalledTimes(1)
|
expect(mockGlob).toBeCalledTimes(1)
|
||||||
expect(mockGlob).toBeCalledWith('art2', 'contentType', false)
|
expect(mockGlob).toBeCalledWith('art2', 'contentType')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -179,18 +154,6 @@ describe('Inputs', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('discussionCategory', () => {
|
|
||||||
it('returns category', () => {
|
|
||||||
mockGetInput.mockReturnValue('Release')
|
|
||||||
expect(inputs.discussionCategory).toBe('Release')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('returns undefined', () => {
|
|
||||||
mockGetInput.mockReturnValue('')
|
|
||||||
expect(inputs.discussionCategory).toBe(undefined)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('draft', () => {
|
describe('draft', () => {
|
||||||
it('returns false', () => {
|
it('returns false', () => {
|
||||||
expect(inputs.draft).toBe(false)
|
expect(inputs.draft).toBe(false)
|
||||||
@@ -201,7 +164,7 @@ describe('Inputs', () => {
|
|||||||
expect(inputs.draft).toBe(true)
|
expect(inputs.draft).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('owner', () => {
|
describe('owner', () => {
|
||||||
it('returns owner from context', function () {
|
it('returns owner from context', function () {
|
||||||
process.env.GITHUB_REPOSITORY = "owner/repo"
|
process.env.GITHUB_REPOSITORY = "owner/repo"
|
||||||
@@ -212,7 +175,7 @@ describe('Inputs', () => {
|
|||||||
mockGetInput.mockReturnValue("owner")
|
mockGetInput.mockReturnValue("owner")
|
||||||
expect(inputs.owner).toBe("owner")
|
expect(inputs.owner).toBe("owner")
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('prerelase', () => {
|
describe('prerelase', () => {
|
||||||
it('returns false', () => {
|
it('returns false', () => {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import {Action} from "../src/Action";
|
import {Action} from "../src/Action";
|
||||||
import * as github from "@actions/github";
|
import * as github from "@actions/github";
|
||||||
import {Inputs} from "../src/Inputs";
|
import {Inputs} from "../src/Inputs";
|
||||||
import {GithubReleases, ReleaseData} from "../src/Releases";
|
import {GithubReleases} from "../src/Releases";
|
||||||
import {GithubArtifactUploader} from "../src/ArtifactUploader";
|
import {GithubArtifactUploader} from "../src/ArtifactUploader";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import {FileArtifactGlobber} from "../src/ArtifactGlobber";
|
import {FileArtifactGlobber} from "../src/ArtifactGlobber";
|
||||||
import {Outputs} from "../src/Outputs";
|
|
||||||
|
|
||||||
// This test is currently intended to be manually run during development. To run:
|
// This test is currently intended to be manually run during development. To run:
|
||||||
// - Make sure you have an environment variable named GITHUB_TOKEN assigned to your token
|
// - Make sure you have an environment variable named GITHUB_TOKEN assigned to your token
|
||||||
@@ -18,14 +17,9 @@ describe.skip('Integration Test', () => {
|
|||||||
const git = github.getOctokit(token)
|
const git = github.getOctokit(token)
|
||||||
|
|
||||||
const inputs = getInputs()
|
const inputs = getInputs()
|
||||||
const outputs = getOutputs()
|
|
||||||
const releases = new GithubReleases(inputs, git)
|
const releases = new GithubReleases(inputs, git)
|
||||||
const uploader = new GithubArtifactUploader(
|
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts)
|
||||||
releases,
|
action = new Action(inputs, releases, uploader)
|
||||||
inputs.replacesArtifacts,
|
|
||||||
inputs.artifactErrorsFailBuild,
|
|
||||||
)
|
|
||||||
action = new Action(inputs, outputs, releases, uploader)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Performs action', async () => {
|
it('Performs action', async () => {
|
||||||
@@ -36,12 +30,10 @@ describe.skip('Integration Test', () => {
|
|||||||
const MockInputs = jest.fn<Inputs, any>(() => {
|
const MockInputs = jest.fn<Inputs, any>(() => {
|
||||||
return {
|
return {
|
||||||
allowUpdates: true,
|
allowUpdates: true,
|
||||||
artifactErrorsFailBuild: false,
|
|
||||||
artifacts: artifacts(),
|
artifacts: artifacts(),
|
||||||
createdReleaseBody: "This release was generated by release-action's integration test",
|
createdReleaseBody: "This release was generated by release-action's integration test",
|
||||||
createdReleaseName: "Releases Action Integration Test 2",
|
createdReleaseName: "Releases Action Integration Test",
|
||||||
commit: "",
|
commit: "",
|
||||||
discussionCategory: 'Release',
|
|
||||||
draft: false,
|
draft: false,
|
||||||
owner: "ncipollo",
|
owner: "ncipollo",
|
||||||
prerelease: false,
|
prerelease: false,
|
||||||
@@ -50,28 +42,17 @@ describe.skip('Integration Test', () => {
|
|||||||
tag: "release-action-test",
|
tag: "release-action-test",
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
updatedReleaseBody: "This release was generated by release-action's integration test",
|
updatedReleaseBody: "This release was generated by release-action's integration test",
|
||||||
updatedReleaseName: "Releases Action Integration Test 2"
|
updatedReleaseName: "Releases Action Integration Test"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return new MockInputs();
|
return new MockInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOutputs(): Outputs {
|
|
||||||
const MockOutputs = jest.fn<Outputs, any>(() => {
|
|
||||||
return {
|
|
||||||
applyReleaseData(releaseData: ReleaseData) {
|
|
||||||
console.log(`Release Data: ${releaseData}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return new MockOutputs()
|
|
||||||
}
|
|
||||||
|
|
||||||
function artifacts() {
|
function artifacts() {
|
||||||
const globber = new FileArtifactGlobber()
|
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}`
|
const artifactString = `~/Desktop/test.txt,blarg.tx, ${artifactPath}`
|
||||||
return globber.globArtifactString(artifactString, "raw", false)
|
return globber.globArtifactString(artifactString, "raw")
|
||||||
}
|
}
|
||||||
|
|
||||||
function getToken(): string {
|
function getToken(): string {
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
const mockSetOutput = jest.fn();
|
|
||||||
|
|
||||||
import {CoreOutputs, Outputs} from "../src/Outputs";
|
|
||||||
import {ReleaseData} from "../src/Releases";
|
|
||||||
|
|
||||||
jest.mock('@actions/core', () => {
|
|
||||||
return {setOutput: mockSetOutput};
|
|
||||||
})
|
|
||||||
|
|
||||||
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'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
15
action.yml
15
action.yml
@@ -6,10 +6,6 @@ inputs:
|
|||||||
description: 'An optional flag which indicates if we should update a release if it already exists. Defaults to false.'
|
description: 'An optional flag which indicates if we should update a release if it already exists. Defaults to false.'
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
artifactErrorsFailBuild:
|
|
||||||
description: 'An optional flag which indicates if artifact read or upload errors should fail the build.'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
artifact:
|
artifact:
|
||||||
deprecationMessage: Use 'artifacts' instead.
|
deprecationMessage: Use 'artifacts' instead.
|
||||||
description: 'An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs)'
|
description: 'An optional set of paths representing artifacts to upload to the release. This may be a single path or a comma delimited list of paths (or globs)'
|
||||||
@@ -34,10 +30,6 @@ inputs:
|
|||||||
commit:
|
commit:
|
||||||
description: "An optional commit reference. This will be used to create the tag if it does not exist."
|
description: "An optional commit reference. This will be used to create the tag if it does not exist."
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
|
||||||
discussionCategory:
|
|
||||||
description: "When provided this will generate a discussion of the specified category. The category must exist otherwise this will cause the action to fail. This isn't used with draft releases"
|
|
||||||
required: false
|
|
||||||
default: ''
|
default: ''
|
||||||
draft:
|
draft:
|
||||||
description: "Optionally marks this release as a draft release. Set to true to enable."
|
description: "Optionally marks this release as a draft release. Set to true to enable."
|
||||||
@@ -87,13 +79,6 @@ inputs:
|
|||||||
description: 'The Github token.'
|
description: 'The Github token.'
|
||||||
required: true
|
required: true
|
||||||
default: ''
|
default: ''
|
||||||
outputs:
|
|
||||||
id:
|
|
||||||
description: 'The identifier of the created release.'
|
|
||||||
html_url:
|
|
||||||
description: 'The HTML URL of the release.'
|
|
||||||
upload_url:
|
|
||||||
description: 'The URL for uploading assets to the release.'
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'lib/Main.js'
|
main: 'lib/Main.js'
|
||||||
|
|||||||
@@ -10,62 +10,53 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.Action = void 0;
|
exports.Action = void 0;
|
||||||
const GithubError_1 = require("./GithubError");
|
const ErrorMessage_1 = require("./ErrorMessage");
|
||||||
class Action {
|
class Action {
|
||||||
constructor(inputs, outputs, releases, uploader) {
|
constructor(inputs, releases, uploader) {
|
||||||
this.inputs = inputs;
|
this.inputs = inputs;
|
||||||
this.outputs = outputs;
|
|
||||||
this.releases = releases;
|
this.releases = releases;
|
||||||
this.uploader = uploader;
|
this.uploader = uploader;
|
||||||
}
|
}
|
||||||
perform() {
|
perform() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const releaseResponse = yield this.createOrUpdateRelease();
|
const releaseResponse = yield this.createOrUpdateRelease();
|
||||||
const releaseData = releaseResponse.data;
|
const releaseId = releaseResponse.data.id;
|
||||||
const releaseId = releaseData.id;
|
const uploadUrl = releaseResponse.data.upload_url;
|
||||||
const uploadUrl = releaseData.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, releaseId, uploadUrl);
|
yield this.uploader.uploadArtifacts(artifacts, releaseId, uploadUrl);
|
||||||
}
|
}
|
||||||
this.outputs.applyReleaseData(releaseData);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
createOrUpdateRelease() {
|
createOrUpdateRelease() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
if (this.inputs.allowUpdates) {
|
if (this.inputs.allowUpdates) {
|
||||||
let getResponse;
|
|
||||||
try {
|
try {
|
||||||
getResponse = yield this.releases.getByTag(this.inputs.tag);
|
const getResponse = yield this.releases.getByTag(this.inputs.tag);
|
||||||
|
return yield this.updateRelease(getResponse.data.id);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
return yield this.checkForMissingReleaseError(error);
|
if (Action.noPublishedRelease(error)) {
|
||||||
|
return yield this.updateDraftOrCreateRelease();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return yield this.updateRelease(getResponse.data.id);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return yield this.createRelease();
|
return yield this.createRelease();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
checkForMissingReleaseError(error) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (Action.noPublishedRelease(error)) {
|
|
||||||
return yield this.updateDraftOrCreateRelease();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
updateRelease(id) {
|
updateRelease(id) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return yield this.releases.update(id, this.inputs.tag, this.inputs.updatedReleaseBody, this.inputs.commit, this.inputs.discussionCategory, this.inputs.draft, this.inputs.updatedReleaseName, this.inputs.prerelease);
|
return yield this.releases.update(id, this.inputs.tag, this.inputs.updatedReleaseBody, this.inputs.commit, this.inputs.draft, this.inputs.updatedReleaseName, this.inputs.prerelease);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static noPublishedRelease(error) {
|
static noPublishedRelease(error) {
|
||||||
const githubError = new GithubError_1.GithubError(error);
|
const errorMessage = new ErrorMessage_1.ErrorMessage(error);
|
||||||
return githubError.status == 404;
|
return errorMessage.status == 404;
|
||||||
}
|
}
|
||||||
updateDraftOrCreateRelease() {
|
updateDraftOrCreateRelease() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -89,7 +80,8 @@ class Action {
|
|||||||
}
|
}
|
||||||
createRelease() {
|
createRelease() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return yield this.releases.create(this.inputs.tag, this.inputs.createdReleaseBody, this.inputs.commit, this.inputs.discussionCategory, this.inputs.draft, this.inputs.createdReleaseName, this.inputs.prerelease);
|
const response = yield this.releases.create(this.inputs.tag, this.inputs.createdReleaseBody, this.inputs.commit, this.inputs.draft, this.inputs.createdReleaseName, this.inputs.prerelease);
|
||||||
|
return response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,41 +27,27 @@ const core = __importStar(require("@actions/core"));
|
|||||||
const Globber_1 = require("./Globber");
|
const Globber_1 = require("./Globber");
|
||||||
const Artifact_1 = require("./Artifact");
|
const Artifact_1 = require("./Artifact");
|
||||||
const untildify_1 = __importDefault(require("untildify"));
|
const untildify_1 = __importDefault(require("untildify"));
|
||||||
const ArtifactPathValidator_1 = require("./ArtifactPathValidator");
|
|
||||||
class FileArtifactGlobber {
|
class FileArtifactGlobber {
|
||||||
constructor(globber = new Globber_1.FileGlobber()) {
|
constructor(globber = new Globber_1.FileGlobber()) {
|
||||||
this.globber = globber;
|
this.globber = globber;
|
||||||
}
|
}
|
||||||
globArtifactString(artifact, contentType, errorsFailBuild) {
|
globArtifactString(artifact, contentType) {
|
||||||
return artifact.split(',')
|
return artifact.split(',')
|
||||||
.map(path => FileArtifactGlobber.expandPath(path))
|
.map(path => FileArtifactGlobber.expandPath(path))
|
||||||
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
.map(pattern => this.globPattern(pattern))
|
||||||
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
|
||||||
.reduce((accumulated, current) => accumulated.concat(current))
|
.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) {
|
globPattern(pattern) {
|
||||||
const paths = this.globber.glob(pattern);
|
const paths = this.globber.glob(pattern);
|
||||||
if (paths.length == 0) {
|
if (paths.length == 0) {
|
||||||
if (errorsFailBuild) {
|
FileArtifactGlobber.reportGlobWarning(pattern);
|
||||||
FileArtifactGlobber.throwGlobError(pattern);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
FileArtifactGlobber.reportGlobWarning(pattern);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return [pattern, paths];
|
return paths;
|
||||||
}
|
|
||||||
static validatePattern(errorsFailBuild, paths, pattern) {
|
|
||||||
const validator = new ArtifactPathValidator_1.ArtifactPathValidator(errorsFailBuild, paths, pattern);
|
|
||||||
return validator.validate();
|
|
||||||
}
|
}
|
||||||
static reportGlobWarning(pattern) {
|
static reportGlobWarning(pattern) {
|
||||||
core.warning(`Artifact pattern :${pattern} did not match any files`);
|
core.warning(`Artifact pattern :${pattern} did not match any files`);
|
||||||
}
|
}
|
||||||
static throwGlobError(pattern) {
|
|
||||||
throw Error(`Artifact pattern :${pattern} did not match any files`);
|
|
||||||
}
|
|
||||||
static expandPath(path) {
|
static expandPath(path) {
|
||||||
return untildify_1.default(path);
|
return untildify_1.default(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.ArtifactPathValidator = void 0;
|
|
||||||
const core = __importStar(require("@actions/core"));
|
|
||||||
const fs_1 = require("fs");
|
|
||||||
class ArtifactPathValidator {
|
|
||||||
constructor(errorsFailBuild, paths, pattern) {
|
|
||||||
this.paths = paths;
|
|
||||||
this.pattern = pattern;
|
|
||||||
this.errorsFailBuild = errorsFailBuild;
|
|
||||||
}
|
|
||||||
validate() {
|
|
||||||
this.verifyPathsNotEmpty();
|
|
||||||
return this.paths.filter((path) => this.verifyNotDirectory(path));
|
|
||||||
}
|
|
||||||
verifyPathsNotEmpty() {
|
|
||||||
if (this.paths.length == 0) {
|
|
||||||
const message = `Artifact pattern:${this.pattern} did not match any files`;
|
|
||||||
this.reportError(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verifyNotDirectory(path) {
|
|
||||||
const isDir = fs_1.statSync(path).isDirectory();
|
|
||||||
if (isDir) {
|
|
||||||
const message = `Artifact is a directory:${path}. Directories can not be uploaded to a release.`;
|
|
||||||
this.reportError(message);
|
|
||||||
}
|
|
||||||
return !isDir;
|
|
||||||
}
|
|
||||||
reportError(message) {
|
|
||||||
if (this.errorsFailBuild) {
|
|
||||||
throw Error(message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.warning(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.ArtifactPathValidator = ArtifactPathValidator;
|
|
||||||
@@ -31,10 +31,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
exports.GithubArtifactUploader = void 0;
|
exports.GithubArtifactUploader = void 0;
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
class GithubArtifactUploader {
|
class GithubArtifactUploader {
|
||||||
constructor(releases, replacesExistingArtifacts = true, throwsUploadErrors = false) {
|
constructor(releases, replacesExistingArtifacts = true) {
|
||||||
this.releases = releases;
|
this.releases = releases;
|
||||||
this.replacesExistingArtifacts = replacesExistingArtifacts;
|
this.replacesExistingArtifacts = replacesExistingArtifacts;
|
||||||
this.throwsUploadErrors = throwsUploadErrors;
|
|
||||||
}
|
}
|
||||||
uploadArtifacts(artifacts, releaseId, uploadUrl) {
|
uploadArtifacts(artifacts, releaseId, uploadUrl) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -58,19 +57,15 @@ class GithubArtifactUploader {
|
|||||||
yield this.uploadArtifact(artifact, releaseId, uploadUrl, retry - 1);
|
yield this.uploadArtifact(artifact, releaseId, uploadUrl, retry - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (this.throwsUploadErrors) {
|
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}.`);
|
||||||
throw Error(`Failed to upload artifact ${artifact.name}. ${error.message}.`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
deleteUpdatedArtifacts(artifacts, releaseId) {
|
deleteUpdatedArtifacts(artifacts, releaseId) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const releaseAssets = yield this.releases.listArtifactsForRelease(releaseId);
|
const response = yield this.releases.listArtifactsForRelease(releaseId);
|
||||||
|
const releaseAssets = response.data;
|
||||||
const assetByName = {};
|
const assetByName = {};
|
||||||
releaseAssets.forEach(asset => {
|
releaseAssets.forEach(asset => {
|
||||||
assetByName[asset.name] = asset;
|
assetByName[asset.name] = asset;
|
||||||
|
|||||||
40
lib/ErrorMessage.js
Normal file
40
lib/ErrorMessage.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ErrorMessage = void 0;
|
||||||
|
const GithubError_1 = require("./GithubError");
|
||||||
|
class ErrorMessage {
|
||||||
|
constructor(error) {
|
||||||
|
this.error = error;
|
||||||
|
this.githubErrors = this.generateGithubErrors();
|
||||||
|
}
|
||||||
|
generateGithubErrors() {
|
||||||
|
const errors = this.error.errors;
|
||||||
|
if (errors instanceof Array) {
|
||||||
|
return errors.map((err) => new GithubError_1.GithubError(err));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get status() {
|
||||||
|
return this.error.status;
|
||||||
|
}
|
||||||
|
hasErrorWithCode(code) {
|
||||||
|
return this.githubErrors.some((err) => err.code == code);
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
const message = this.error.message;
|
||||||
|
const errors = this.githubErrors;
|
||||||
|
const status = this.status;
|
||||||
|
if (errors.length > 0) {
|
||||||
|
return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `Error ${status}: ${message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorBulletedList(errors) {
|
||||||
|
return errors.map((err) => `- ${err}`).join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ErrorMessage = ErrorMessage;
|
||||||
@@ -1,40 +1,57 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.GithubError = void 0;
|
exports.GithubError = void 0;
|
||||||
const GithubErrorDetail_1 = require("./GithubErrorDetail");
|
|
||||||
class GithubError {
|
class GithubError {
|
||||||
constructor(error) {
|
constructor(error) {
|
||||||
this.error = error;
|
this.error = error;
|
||||||
this.githubErrors = this.generateGithubErrors();
|
|
||||||
}
|
}
|
||||||
generateGithubErrors() {
|
get code() {
|
||||||
const errors = this.error.errors;
|
return this.error.code;
|
||||||
if (errors instanceof Array) {
|
|
||||||
return errors.map((err) => new GithubErrorDetail_1.GithubErrorDetail(err));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get status() {
|
|
||||||
return this.error.status;
|
|
||||||
}
|
|
||||||
hasErrorWithCode(code) {
|
|
||||||
return this.githubErrors.some((err) => err.code == code);
|
|
||||||
}
|
}
|
||||||
toString() {
|
toString() {
|
||||||
const message = this.error.message;
|
const code = this.error.code;
|
||||||
const errors = this.githubErrors;
|
switch (code) {
|
||||||
const status = this.status;
|
case 'missing':
|
||||||
if (errors.length > 0) {
|
return this.missingResourceMessage();
|
||||||
return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`;
|
case 'missing_field':
|
||||||
}
|
return this.missingFieldMessage();
|
||||||
else {
|
case 'invalid':
|
||||||
return `Error ${status}: ${message}`;
|
return this.invalidFieldMessage();
|
||||||
|
case 'already_exists':
|
||||||
|
return this.resourceAlreadyExists();
|
||||||
|
default:
|
||||||
|
return this.customErrorMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorBulletedList(errors) {
|
customErrorMessage() {
|
||||||
return errors.map((err) => `- ${err}`).join("\n");
|
const message = this.error.message;
|
||||||
|
const documentation = this.error.documentation_url;
|
||||||
|
let documentationMessage;
|
||||||
|
if (documentation) {
|
||||||
|
documentationMessage = `\nPlease see ${documentation}.`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
documentationMessage = "";
|
||||||
|
}
|
||||||
|
return `${message}${documentationMessage}`;
|
||||||
|
}
|
||||||
|
invalidFieldMessage() {
|
||||||
|
const resource = this.error.resource;
|
||||||
|
const field = this.error.field;
|
||||||
|
return `The ${field} field on ${resource} is an invalid format.`;
|
||||||
|
}
|
||||||
|
missingResourceMessage() {
|
||||||
|
const resource = this.error.resource;
|
||||||
|
return `${resource} does not exist.`;
|
||||||
|
}
|
||||||
|
missingFieldMessage() {
|
||||||
|
const resource = this.error.resource;
|
||||||
|
const field = this.error.field;
|
||||||
|
return `The ${field} field on ${resource} is missing.`;
|
||||||
|
}
|
||||||
|
resourceAlreadyExists() {
|
||||||
|
const resource = this.error.resource;
|
||||||
|
return `${resource} already exists.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.GithubError = GithubError;
|
exports.GithubError = GithubError;
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.GithubErrorDetail = void 0;
|
|
||||||
class GithubErrorDetail {
|
|
||||||
constructor(error) {
|
|
||||||
this.error = error;
|
|
||||||
}
|
|
||||||
get code() {
|
|
||||||
return this.error.code;
|
|
||||||
}
|
|
||||||
toString() {
|
|
||||||
const code = this.error.code;
|
|
||||||
switch (code) {
|
|
||||||
case 'missing':
|
|
||||||
return this.missingResourceMessage();
|
|
||||||
case 'missing_field':
|
|
||||||
return this.missingFieldMessage();
|
|
||||||
case 'invalid':
|
|
||||||
return this.invalidFieldMessage();
|
|
||||||
case 'already_exists':
|
|
||||||
return this.resourceAlreadyExists();
|
|
||||||
default:
|
|
||||||
return this.customErrorMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customErrorMessage() {
|
|
||||||
const message = this.error.message;
|
|
||||||
const documentation = this.error.documentation_url;
|
|
||||||
let documentationMessage;
|
|
||||||
if (documentation) {
|
|
||||||
documentationMessage = `\nPlease see ${documentation}.`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
documentationMessage = "";
|
|
||||||
}
|
|
||||||
return `${message}${documentationMessage}`;
|
|
||||||
}
|
|
||||||
invalidFieldMessage() {
|
|
||||||
const resource = this.error.resource;
|
|
||||||
const field = this.error.field;
|
|
||||||
return `The ${field} field on ${resource} is an invalid format.`;
|
|
||||||
}
|
|
||||||
missingResourceMessage() {
|
|
||||||
const resource = this.error.resource;
|
|
||||||
return `${resource} does not exist.`;
|
|
||||||
}
|
|
||||||
missingFieldMessage() {
|
|
||||||
const resource = this.error.resource;
|
|
||||||
const field = this.error.field;
|
|
||||||
return `The ${field} field on ${resource} is missing.`;
|
|
||||||
}
|
|
||||||
resourceAlreadyExists() {
|
|
||||||
const resource = this.error.resource;
|
|
||||||
return `${resource} already exists.`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.GithubErrorDetail = GithubErrorDetail;
|
|
||||||
@@ -42,14 +42,10 @@ class CoreInputs {
|
|||||||
contentType = 'raw';
|
contentType = 'raw';
|
||||||
}
|
}
|
||||||
return this.artifactGlobber
|
return this.artifactGlobber
|
||||||
.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild);
|
.globArtifactString(artifacts, contentType);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
get artifactErrorsFailBuild() {
|
|
||||||
const allow = core.getInput('artifactErrorsFailBuild');
|
|
||||||
return allow == 'true';
|
|
||||||
}
|
|
||||||
get createdReleaseBody() {
|
get createdReleaseBody() {
|
||||||
if (CoreInputs.omitBody)
|
if (CoreInputs.omitBody)
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -77,13 +73,6 @@ class CoreInputs {
|
|||||||
return undefined;
|
return undefined;
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
get discussionCategory() {
|
|
||||||
const category = core.getInput('discussionCategory');
|
|
||||||
if (category) {
|
|
||||||
return category;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
static get omitName() {
|
static get omitName() {
|
||||||
return core.getInput('omitName') == 'true';
|
return core.getInput('omitName') == 'true';
|
||||||
}
|
}
|
||||||
|
|||||||
12
lib/Main.js
12
lib/Main.js
@@ -35,8 +35,7 @@ const Releases_1 = require("./Releases");
|
|||||||
const Action_1 = require("./Action");
|
const Action_1 = require("./Action");
|
||||||
const ArtifactUploader_1 = require("./ArtifactUploader");
|
const ArtifactUploader_1 = require("./ArtifactUploader");
|
||||||
const ArtifactGlobber_1 = require("./ArtifactGlobber");
|
const ArtifactGlobber_1 = require("./ArtifactGlobber");
|
||||||
const GithubError_1 = require("./GithubError");
|
const ErrorMessage_1 = require("./ErrorMessage");
|
||||||
const Outputs_1 = require("./Outputs");
|
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
@@ -44,8 +43,8 @@ function run() {
|
|||||||
yield action.perform();
|
yield action.perform();
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
const githubError = new GithubError_1.GithubError(error);
|
const errorMessage = new ErrorMessage_1.ErrorMessage(error);
|
||||||
core.setFailed(githubError.toString());
|
core.setFailed(errorMessage.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -55,9 +54,8 @@ function createAction() {
|
|||||||
const git = github.getOctokit(token);
|
const git = github.getOctokit(token);
|
||||||
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 outputs = new Outputs_1.CoreOutputs();
|
|
||||||
const releases = new Releases_1.GithubReleases(inputs, git);
|
const releases = new Releases_1.GithubReleases(inputs, git);
|
||||||
const uploader = new ArtifactUploader_1.GithubArtifactUploader(releases, inputs.replacesArtifacts, inputs.artifactErrorsFailBuild);
|
const uploader = new ArtifactUploader_1.GithubArtifactUploader(releases, inputs.replacesArtifacts);
|
||||||
return new Action_1.Action(inputs, outputs, releases, uploader);
|
return new Action_1.Action(inputs, releases, uploader);
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.CoreOutputs = void 0;
|
|
||||||
const core = __importStar(require("@actions/core"));
|
|
||||||
class CoreOutputs {
|
|
||||||
applyReleaseData(releaseData) {
|
|
||||||
core.setOutput('id', releaseData.id);
|
|
||||||
core.setOutput('html_url', releaseData.html_url);
|
|
||||||
core.setOutput('upload_url', releaseData.upload_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.CoreOutputs = CoreOutputs;
|
|
||||||
@@ -15,13 +15,12 @@ class GithubReleases {
|
|||||||
this.inputs = inputs;
|
this.inputs = inputs;
|
||||||
this.git = git;
|
this.git = git;
|
||||||
}
|
}
|
||||||
create(tag, body, commitHash, discussionCategory, draft, name, prerelease) {
|
create(tag, body, commitHash, draft, name, prerelease) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// noinspection TypeScriptValidateJSTypes
|
// noinspection TypeScriptValidateJSTypes
|
||||||
return this.git.repos.createRelease({
|
return this.git.repos.createRelease({
|
||||||
body: body,
|
body: body,
|
||||||
name: name,
|
name: name,
|
||||||
discussion_category_name: discussionCategory,
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
prerelease: prerelease,
|
prerelease: prerelease,
|
||||||
@@ -51,7 +50,7 @@ class GithubReleases {
|
|||||||
}
|
}
|
||||||
listArtifactsForRelease(releaseId) {
|
listArtifactsForRelease(releaseId) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return this.git.paginate(this.git.repos.listReleaseAssets, {
|
return this.git.repos.listReleaseAssets({
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
release_id: releaseId,
|
release_id: releaseId,
|
||||||
repo: this.inputs.repo
|
repo: this.inputs.repo
|
||||||
@@ -66,14 +65,13 @@ class GithubReleases {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
update(id, tag, body, commitHash, discussionCategory, draft, name, prerelease) {
|
update(id, tag, body, commitHash, draft, name, prerelease) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// noinspection TypeScriptValidateJSTypes
|
// noinspection TypeScriptValidateJSTypes
|
||||||
return this.git.repos.updateRelease({
|
return this.git.repos.updateRelease({
|
||||||
release_id: id,
|
release_id: id,
|
||||||
body: body,
|
body: body,
|
||||||
name: name,
|
name: name,
|
||||||
discussion_category_name: discussionCategory,
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
prerelease: prerelease,
|
prerelease: prerelease,
|
||||||
|
|||||||
15
node_modules/.yarn-integrity
generated
vendored
15
node_modules/.yarn-integrity
generated
vendored
@@ -15,8 +15,8 @@
|
|||||||
"@types/node@^14.14.25",
|
"@types/node@^14.14.25",
|
||||||
"glob@^7.1.4",
|
"glob@^7.1.4",
|
||||||
"jest-circus@^26.6.3",
|
"jest-circus@^26.6.3",
|
||||||
"jest@^26.6.3",
|
"jest@^26.1.0",
|
||||||
"ts-jest@^26.5.6",
|
"ts-jest@^26.5.1",
|
||||||
"typescript@^4.1.4",
|
"typescript@^4.1.4",
|
||||||
"untildify@^4.0.0"
|
"untildify@^4.0.0"
|
||||||
],
|
],
|
||||||
@@ -112,6 +112,7 @@
|
|||||||
"@types/istanbul-lib-coverage@^2.0.1": "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762",
|
"@types/istanbul-lib-coverage@^2.0.1": "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762",
|
||||||
"@types/istanbul-lib-report@*": "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686",
|
"@types/istanbul-lib-report@*": "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686",
|
||||||
"@types/istanbul-reports@^3.0.0": "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821",
|
"@types/istanbul-reports@^3.0.0": "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821",
|
||||||
|
"@types/jest@26.x": "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307",
|
||||||
"@types/jest@^26.0.20": "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307",
|
"@types/jest@^26.0.20": "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307",
|
||||||
"@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-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93",
|
"@types/node@*": "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93",
|
||||||
@@ -285,7 +286,7 @@
|
|||||||
"has-values@^0.1.4": "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771",
|
"has-values@^0.1.4": "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771",
|
||||||
"has-values@^1.0.0": "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f",
|
"has-values@^1.0.0": "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f",
|
||||||
"has@^1.0.3": "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796",
|
"has@^1.0.3": "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796",
|
||||||
"hosted-git-info@^2.1.4": "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9",
|
"hosted-git-info@^2.1.4": "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488",
|
||||||
"html-encoding-sniffer@^2.0.1": "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3",
|
"html-encoding-sniffer@^2.0.1": "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3",
|
||||||
"html-escaper@^2.0.0": "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453",
|
"html-escaper@^2.0.0": "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453",
|
||||||
"http-signature@~1.2.0": "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1",
|
"http-signature@~1.2.0": "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1",
|
||||||
@@ -367,7 +368,7 @@
|
|||||||
"jest-validate@^26.6.2": "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec",
|
"jest-validate@^26.6.2": "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec",
|
||||||
"jest-watcher@^26.6.2": "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975",
|
"jest-watcher@^26.6.2": "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975",
|
||||||
"jest-worker@^26.6.2": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed",
|
"jest-worker@^26.6.2": "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed",
|
||||||
"jest@^26.6.3": "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef",
|
"jest@^26.1.0": "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef",
|
||||||
"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",
|
||||||
"js-yaml@^3.13.1": "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537",
|
"js-yaml@^3.13.1": "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537",
|
||||||
"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",
|
||||||
@@ -393,8 +394,8 @@
|
|||||||
"lines-and-columns@^1.1.6": "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00",
|
"lines-and-columns@^1.1.6": "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00",
|
||||||
"locate-path@^5.0.0": "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0",
|
"locate-path@^5.0.0": "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0",
|
||||||
"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@4.x": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c",
|
"lodash@4.x": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52",
|
||||||
"lodash@^4.17.19": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c",
|
"lodash@^4.17.19": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52",
|
||||||
"lru-cache@^6.0.0": "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94",
|
"lru-cache@^6.0.0": "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94",
|
||||||
"make-dir@^3.0.0": "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f",
|
"make-dir@^3.0.0": "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f",
|
||||||
"make-error@1.x": "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2",
|
"make-error@1.x": "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2",
|
||||||
@@ -567,7 +568,7 @@
|
|||||||
"tough-cookie@^3.0.1": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2",
|
"tough-cookie@^3.0.1": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2",
|
||||||
"tough-cookie@~2.5.0": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2",
|
"tough-cookie@~2.5.0": "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2",
|
||||||
"tr46@^2.0.2": "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479",
|
"tr46@^2.0.2": "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479",
|
||||||
"ts-jest@^26.5.6": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35",
|
"ts-jest@^26.5.1": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.1.tgz#4d53ee4481552f57c1624f0bd3425c8b17996150",
|
||||||
"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",
|
||||||
"tunnel@0.0.6": "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c",
|
"tunnel@0.0.6": "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c",
|
||||||
"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",
|
||||||
|
|||||||
@@ -32,9 +32,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.20",
|
"@types/jest": "^26.0.20",
|
||||||
"@types/node": "^14.14.25",
|
"@types/node": "^14.14.25",
|
||||||
"jest": "^26.6.3",
|
"jest": "^26.1.0",
|
||||||
"jest-circus": "^26.6.3",
|
"jest-circus": "^26.6.3",
|
||||||
"ts-jest": "^26.5.6",
|
"ts-jest": "^26.5.1",
|
||||||
"typescript": "^4.1.4"
|
"typescript": "^4.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +1,53 @@
|
|||||||
import {Inputs} from "./Inputs";
|
import {Inputs} from "./Inputs";
|
||||||
import {
|
import {CreateReleaseResponse, Releases, UpdateReleaseResponse} from "./Releases";
|
||||||
CreateOrUpdateReleaseResponse,
|
|
||||||
CreateReleaseResponse,
|
|
||||||
ReleaseByTagResponse,
|
|
||||||
Releases,
|
|
||||||
UpdateReleaseResponse
|
|
||||||
} from "./Releases";
|
|
||||||
import {ArtifactUploader} from "./ArtifactUploader";
|
import {ArtifactUploader} from "./ArtifactUploader";
|
||||||
import {GithubError} from "./GithubError";
|
import {ErrorMessage} from "./ErrorMessage";
|
||||||
import {Outputs} from "./Outputs";
|
|
||||||
|
|
||||||
export class Action {
|
export class Action {
|
||||||
private inputs: Inputs
|
private inputs: Inputs
|
||||||
private outputs: Outputs
|
|
||||||
private releases: Releases
|
private releases: Releases
|
||||||
private uploader: ArtifactUploader
|
private uploader: ArtifactUploader
|
||||||
|
|
||||||
constructor(inputs: Inputs, outputs: Outputs, releases: Releases, uploader: ArtifactUploader) {
|
constructor(inputs: Inputs, releases: Releases, uploader: ArtifactUploader) {
|
||||||
this.inputs = inputs
|
this.inputs = inputs
|
||||||
this.outputs = outputs
|
|
||||||
this.releases = releases
|
this.releases = releases
|
||||||
this.uploader = uploader
|
this.uploader = uploader
|
||||||
}
|
}
|
||||||
|
|
||||||
async perform() {
|
async perform() {
|
||||||
const releaseResponse = await this.createOrUpdateRelease();
|
const releaseResponse = await this.createOrUpdateRelease();
|
||||||
const releaseData = releaseResponse.data
|
const releaseId = releaseResponse.data.id
|
||||||
const releaseId = releaseData.id
|
const uploadUrl = releaseResponse.data.upload_url
|
||||||
const uploadUrl = releaseData.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, releaseId, uploadUrl)
|
await this.uploader.uploadArtifacts(artifacts, releaseId, uploadUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.outputs.applyReleaseData(releaseData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createOrUpdateRelease(): Promise<CreateOrUpdateReleaseResponse> {
|
private async createOrUpdateRelease(): Promise<CreateReleaseResponse | UpdateReleaseResponse> {
|
||||||
if (this.inputs.allowUpdates) {
|
if (this.inputs.allowUpdates) {
|
||||||
let getResponse: ReleaseByTagResponse
|
|
||||||
try {
|
try {
|
||||||
getResponse = await this.releases.getByTag(this.inputs.tag)
|
const getResponse = await this.releases.getByTag(this.inputs.tag)
|
||||||
|
return await this.updateRelease(getResponse.data.id)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return await this.checkForMissingReleaseError(error)
|
if (Action.noPublishedRelease(error)) {
|
||||||
|
return await this.updateDraftOrCreateRelease()
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.updateRelease(getResponse.data.id)
|
|
||||||
} else {
|
} else {
|
||||||
return await this.createRelease()
|
return await this.createRelease()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async checkForMissingReleaseError(error: Error): Promise<CreateOrUpdateReleaseResponse> {
|
|
||||||
if (Action.noPublishedRelease(error)) {
|
|
||||||
return await this.updateDraftOrCreateRelease()
|
|
||||||
} else {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async updateRelease(id: number): Promise<UpdateReleaseResponse> {
|
private async updateRelease(id: number): Promise<UpdateReleaseResponse> {
|
||||||
return await this.releases.update(
|
return await this.releases.update(
|
||||||
id,
|
id,
|
||||||
this.inputs.tag,
|
this.inputs.tag,
|
||||||
this.inputs.updatedReleaseBody,
|
this.inputs.updatedReleaseBody,
|
||||||
this.inputs.commit,
|
this.inputs.commit,
|
||||||
this.inputs.discussionCategory,
|
|
||||||
this.inputs.draft,
|
this.inputs.draft,
|
||||||
this.inputs.updatedReleaseName,
|
this.inputs.updatedReleaseName,
|
||||||
this.inputs.prerelease
|
this.inputs.prerelease
|
||||||
@@ -74,8 +55,8 @@ export class Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static noPublishedRelease(error: any): boolean {
|
private static noPublishedRelease(error: any): boolean {
|
||||||
const githubError = new GithubError(error)
|
const errorMessage = new ErrorMessage(error)
|
||||||
return githubError.status == 404
|
return errorMessage.status == 404
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateDraftOrCreateRelease(): Promise<CreateReleaseResponse | UpdateReleaseResponse> {
|
private async updateDraftOrCreateRelease(): Promise<CreateReleaseResponse | UpdateReleaseResponse> {
|
||||||
@@ -97,14 +78,15 @@ export class Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async createRelease(): Promise<CreateReleaseResponse> {
|
private async createRelease(): Promise<CreateReleaseResponse> {
|
||||||
return await this.releases.create(
|
const response = await this.releases.create(
|
||||||
this.inputs.tag,
|
this.inputs.tag,
|
||||||
this.inputs.createdReleaseBody,
|
this.inputs.createdReleaseBody,
|
||||||
this.inputs.commit,
|
this.inputs.commit,
|
||||||
this.inputs.discussionCategory,
|
|
||||||
this.inputs.draft,
|
this.inputs.draft,
|
||||||
this.inputs.createdReleaseName,
|
this.inputs.createdReleaseName,
|
||||||
this.inputs.prerelease
|
this.inputs.prerelease
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import * as core from '@actions/core';
|
|||||||
import {Globber, FileGlobber} from "./Globber";
|
import {Globber, FileGlobber} from "./Globber";
|
||||||
import {Artifact} from "./Artifact";
|
import {Artifact} from "./Artifact";
|
||||||
import untildify from "untildify";
|
import untildify from "untildify";
|
||||||
import {ArtifactPathValidator} from "./ArtifactPathValidator";
|
|
||||||
|
|
||||||
export interface ArtifactGlobber {
|
export interface ArtifactGlobber {
|
||||||
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[]
|
globArtifactString(artifact: string, contentType: string): Artifact[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileArtifactGlobber implements ArtifactGlobber {
|
export class FileArtifactGlobber implements ArtifactGlobber {
|
||||||
@@ -15,40 +14,26 @@ export class FileArtifactGlobber implements ArtifactGlobber {
|
|||||||
this.globber = globber
|
this.globber = globber
|
||||||
}
|
}
|
||||||
|
|
||||||
globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[] {
|
globArtifactString(artifact: string, contentType: string): Artifact[] {
|
||||||
return artifact.split(',')
|
return artifact.split(',')
|
||||||
.map(path => FileArtifactGlobber.expandPath(path))
|
.map(path => FileArtifactGlobber.expandPath(path))
|
||||||
.map(pattern => this.globPattern(pattern, errorsFailBuild))
|
.map(pattern => this.globPattern(pattern))
|
||||||
.map((globResult) => FileArtifactGlobber.validatePattern(errorsFailBuild, globResult[1], globResult[0]))
|
|
||||||
.reduce((accumulated, current) => accumulated.concat(current))
|
.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[]] {
|
private globPattern(pattern: string): string[] {
|
||||||
const paths = this.globber.glob(pattern)
|
const paths = this.globber.glob(pattern)
|
||||||
if (paths.length == 0) {
|
if (paths.length == 0) {
|
||||||
if (errorsFailBuild) {
|
FileArtifactGlobber.reportGlobWarning(pattern)
|
||||||
FileArtifactGlobber.throwGlobError(pattern)
|
|
||||||
} else {
|
|
||||||
FileArtifactGlobber.reportGlobWarning(pattern)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return [pattern, paths]
|
return paths
|
||||||
}
|
|
||||||
|
|
||||||
private static validatePattern(errorsFailBuild: boolean, paths: string[], pattern: string): string[] {
|
|
||||||
const validator = new ArtifactPathValidator(errorsFailBuild, paths, pattern)
|
|
||||||
return validator.validate()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static reportGlobWarning(pattern: string) {
|
private static reportGlobWarning(pattern: string) {
|
||||||
core.warning(`Artifact pattern :${pattern} did not match any files`)
|
core.warning(`Artifact pattern :${pattern} did not match any files`)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static throwGlobError(pattern: string) {
|
|
||||||
throw Error(`Artifact pattern :${pattern} did not match any files`)
|
|
||||||
}
|
|
||||||
|
|
||||||
private static expandPath(path: string): string {
|
private static expandPath(path: string): string {
|
||||||
return untildify(path)
|
return untildify(path)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
import {statSync} from "fs";
|
|
||||||
|
|
||||||
export class ArtifactPathValidator {
|
|
||||||
private readonly errorsFailBuild: boolean;
|
|
||||||
private paths: string[];
|
|
||||||
private readonly pattern: string
|
|
||||||
|
|
||||||
constructor(errorsFailBuild: boolean, paths: string[], pattern: string) {
|
|
||||||
this.paths = paths;
|
|
||||||
this.pattern = pattern
|
|
||||||
this.errorsFailBuild = errorsFailBuild;
|
|
||||||
}
|
|
||||||
|
|
||||||
validate(): string[] {
|
|
||||||
this.verifyPathsNotEmpty()
|
|
||||||
return this.paths.filter((path) => this.verifyNotDirectory(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
private verifyPathsNotEmpty() {
|
|
||||||
if (this.paths.length == 0) {
|
|
||||||
const message = `Artifact pattern:${this.pattern} did not match any files`
|
|
||||||
this.reportError(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private verifyNotDirectory(path: string): boolean {
|
|
||||||
const isDir = statSync(path).isDirectory()
|
|
||||||
if (isDir) {
|
|
||||||
const message = `Artifact is a directory:${path}. Directories can not be uploaded to a release.`
|
|
||||||
this.reportError(message)
|
|
||||||
}
|
|
||||||
return !isDir
|
|
||||||
}
|
|
||||||
|
|
||||||
private reportError(message: string) {
|
|
||||||
if (this.errorsFailBuild) {
|
|
||||||
throw Error(message)
|
|
||||||
} else {
|
|
||||||
core.warning(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ export class GithubArtifactUploader implements ArtifactUploader {
|
|||||||
constructor(
|
constructor(
|
||||||
private releases: Releases,
|
private releases: Releases,
|
||||||
private replacesExistingArtifacts: boolean = true,
|
private replacesExistingArtifacts: boolean = true,
|
||||||
private throwsUploadErrors: boolean = false,
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,17 +41,14 @@ export class GithubArtifactUploader implements ArtifactUploader {
|
|||||||
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}. Retrying...`)
|
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}. Retrying...`)
|
||||||
await this.uploadArtifact(artifact, releaseId, uploadUrl, retry - 1)
|
await this.uploadArtifact(artifact, releaseId, uploadUrl, retry - 1)
|
||||||
} else {
|
} else {
|
||||||
if (this.throwsUploadErrors) {
|
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}.`)
|
||||||
throw Error(`Failed to upload artifact ${artifact.name}. ${error.message}.`)
|
|
||||||
} else {
|
|
||||||
core.warning(`Failed to upload artifact ${artifact.name}. ${error.message}.`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async deleteUpdatedArtifacts(artifacts: Artifact[], releaseId: number): Promise<void> {
|
private async deleteUpdatedArtifacts(artifacts: Artifact[], releaseId: number): Promise<void> {
|
||||||
const releaseAssets = await this.releases.listArtifactsForRelease(releaseId)
|
const response = await this.releases.listArtifactsForRelease(releaseId)
|
||||||
|
const releaseAssets = response.data
|
||||||
const assetByName: Record<string, { id: number; name: string }> = {}
|
const assetByName: Record<string, { id: number; name: string }> = {}
|
||||||
releaseAssets.forEach(asset => {
|
releaseAssets.forEach(asset => {
|
||||||
assetByName[asset.name] = asset
|
assetByName[asset.name] = asset
|
||||||
|
|||||||
44
src/ErrorMessage.ts
Normal file
44
src/ErrorMessage.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import {GithubError} from "./GithubError"
|
||||||
|
|
||||||
|
export class ErrorMessage {
|
||||||
|
private error: any
|
||||||
|
private githubErrors: GithubError[]
|
||||||
|
|
||||||
|
constructor(error: any) {
|
||||||
|
this.error = error
|
||||||
|
this.githubErrors = this.generateGithubErrors()
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateGithubErrors(): GithubError[] {
|
||||||
|
const errors = this.error.errors
|
||||||
|
if (errors instanceof Array) {
|
||||||
|
return errors.map((err) => new GithubError(err))
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get status(): number {
|
||||||
|
return this.error.status
|
||||||
|
}
|
||||||
|
|
||||||
|
hasErrorWithCode(code: String): boolean {
|
||||||
|
return this.githubErrors.some((err) => err.code == code)
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
const message = this.error.message
|
||||||
|
const errors = this.githubErrors
|
||||||
|
const status = this.status
|
||||||
|
if (errors.length > 0) {
|
||||||
|
return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`
|
||||||
|
} else {
|
||||||
|
return `Error ${status}: ${message}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private errorBulletedList(errors: GithubError[]): string {
|
||||||
|
return errors.map((err) => `- ${err}`).join("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,44 +1,65 @@
|
|||||||
import {GithubErrorDetail} from "./GithubErrorDetail"
|
|
||||||
|
|
||||||
export class GithubError {
|
export class GithubError {
|
||||||
private error: any
|
private error: any;
|
||||||
private readonly githubErrors: GithubErrorDetail[]
|
|
||||||
|
|
||||||
constructor(error: any) {
|
constructor(error: any) {
|
||||||
this.error = error
|
this.error = error
|
||||||
this.githubErrors = this.generateGithubErrors()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateGithubErrors(): GithubErrorDetail[] {
|
get code(): string {
|
||||||
const errors = this.error.errors
|
return this.error.code
|
||||||
if (errors instanceof Array) {
|
|
||||||
return errors.map((err) => new GithubErrorDetail(err))
|
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get status(): number {
|
|
||||||
return this.error.status
|
|
||||||
}
|
|
||||||
|
|
||||||
hasErrorWithCode(code: String): boolean {
|
|
||||||
return this.githubErrors.some((err) => err.code == code)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
const message = this.error.message
|
const code = this.error.code
|
||||||
const errors = this.githubErrors
|
switch (code) {
|
||||||
const status = this.status
|
case 'missing':
|
||||||
if (errors.length > 0) {
|
return this.missingResourceMessage()
|
||||||
return `Error ${status}: ${message}\nErrors:\n${this.errorBulletedList(errors)}`
|
case 'missing_field':
|
||||||
} else {
|
return this.missingFieldMessage()
|
||||||
return `Error ${status}: ${message}`
|
case 'invalid':
|
||||||
|
return this.invalidFieldMessage()
|
||||||
|
case 'already_exists':
|
||||||
|
return this.resourceAlreadyExists()
|
||||||
|
default:
|
||||||
|
return this.customErrorMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private errorBulletedList(errors: GithubErrorDetail[]): string {
|
private customErrorMessage(): string {
|
||||||
return errors.map((err) => `- ${err}`).join("\n")
|
const message = this.error.message;
|
||||||
|
const documentation = this.error.documentation_url
|
||||||
|
|
||||||
|
let documentationMessage: string
|
||||||
|
if (documentation) {
|
||||||
|
documentationMessage = `\nPlease see ${documentation}.`
|
||||||
|
} else {
|
||||||
|
documentationMessage = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${message}${documentationMessage}`
|
||||||
|
}
|
||||||
|
|
||||||
|
private invalidFieldMessage(): string {
|
||||||
|
const resource = this.error.resource
|
||||||
|
const field = this.error.field
|
||||||
|
|
||||||
|
return `The ${field} field on ${resource} is an invalid format.`
|
||||||
|
}
|
||||||
|
|
||||||
|
private missingResourceMessage(): string {
|
||||||
|
const resource = this.error.resource
|
||||||
|
return `${resource} does not exist.`
|
||||||
|
}
|
||||||
|
|
||||||
|
private missingFieldMessage(): string {
|
||||||
|
const resource = this.error.resource
|
||||||
|
const field = this.error.field
|
||||||
|
|
||||||
|
return `The ${field} field on ${resource} is missing.`
|
||||||
|
}
|
||||||
|
|
||||||
|
private resourceAlreadyExists(): string {
|
||||||
|
const resource = this.error.resource
|
||||||
|
return `${resource} already exists.`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
export class GithubErrorDetail {
|
|
||||||
private error: any;
|
|
||||||
|
|
||||||
constructor(error: any) {
|
|
||||||
this.error = error
|
|
||||||
}
|
|
||||||
|
|
||||||
get code(): string {
|
|
||||||
return this.error.code
|
|
||||||
}
|
|
||||||
|
|
||||||
toString(): string {
|
|
||||||
const code = this.error.code
|
|
||||||
switch (code) {
|
|
||||||
case 'missing':
|
|
||||||
return this.missingResourceMessage()
|
|
||||||
case 'missing_field':
|
|
||||||
return this.missingFieldMessage()
|
|
||||||
case 'invalid':
|
|
||||||
return this.invalidFieldMessage()
|
|
||||||
case 'already_exists':
|
|
||||||
return this.resourceAlreadyExists()
|
|
||||||
default:
|
|
||||||
return this.customErrorMessage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private customErrorMessage(): string {
|
|
||||||
const message = this.error.message;
|
|
||||||
const documentation = this.error.documentation_url
|
|
||||||
|
|
||||||
let documentationMessage: string
|
|
||||||
if (documentation) {
|
|
||||||
documentationMessage = `\nPlease see ${documentation}.`
|
|
||||||
} else {
|
|
||||||
documentationMessage = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${message}${documentationMessage}`
|
|
||||||
}
|
|
||||||
|
|
||||||
private invalidFieldMessage(): string {
|
|
||||||
const resource = this.error.resource
|
|
||||||
const field = this.error.field
|
|
||||||
|
|
||||||
return `The ${field} field on ${resource} is an invalid format.`
|
|
||||||
}
|
|
||||||
|
|
||||||
private missingResourceMessage(): string {
|
|
||||||
const resource = this.error.resource
|
|
||||||
return `${resource} does not exist.`
|
|
||||||
}
|
|
||||||
|
|
||||||
private missingFieldMessage(): string {
|
|
||||||
const resource = this.error.resource
|
|
||||||
const field = this.error.field
|
|
||||||
|
|
||||||
return `The ${field} field on ${resource} is missing.`
|
|
||||||
}
|
|
||||||
|
|
||||||
private resourceAlreadyExists(): string {
|
|
||||||
const resource = this.error.resource
|
|
||||||
return `${resource} already exists.`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,12 +6,10 @@ import {Artifact} from './Artifact';
|
|||||||
|
|
||||||
export interface Inputs {
|
export interface Inputs {
|
||||||
readonly allowUpdates: boolean
|
readonly allowUpdates: boolean
|
||||||
readonly artifactErrorsFailBuild: boolean
|
|
||||||
readonly artifacts: Artifact[]
|
readonly artifacts: Artifact[]
|
||||||
readonly commit: string
|
readonly commit: string
|
||||||
readonly createdReleaseBody?: string
|
readonly createdReleaseBody?: string
|
||||||
readonly createdReleaseName?: string
|
readonly createdReleaseName?: string
|
||||||
readonly discussionCategory?: string
|
|
||||||
readonly draft: boolean
|
readonly draft: boolean
|
||||||
readonly owner: string
|
readonly owner: string
|
||||||
readonly prerelease: boolean
|
readonly prerelease: boolean
|
||||||
@@ -48,16 +46,11 @@ export class CoreInputs implements Inputs {
|
|||||||
contentType = 'raw'
|
contentType = 'raw'
|
||||||
}
|
}
|
||||||
return this.artifactGlobber
|
return this.artifactGlobber
|
||||||
.globArtifactString(artifacts, contentType, this.artifactErrorsFailBuild)
|
.globArtifactString(artifacts, contentType)
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
get artifactErrorsFailBuild(): boolean {
|
|
||||||
const allow = core.getInput('artifactErrorsFailBuild')
|
|
||||||
return allow == 'true'
|
|
||||||
}
|
|
||||||
|
|
||||||
get createdReleaseBody(): string | undefined {
|
get createdReleaseBody(): string | undefined {
|
||||||
if (CoreInputs.omitBody) return undefined
|
if (CoreInputs.omitBody) return undefined
|
||||||
return this.body
|
return this.body
|
||||||
@@ -67,7 +60,7 @@ export class CoreInputs implements Inputs {
|
|||||||
return core.getInput('omitBody') == 'true'
|
return core.getInput('omitBody') == 'true'
|
||||||
}
|
}
|
||||||
|
|
||||||
private get body(): string | undefined {
|
private get body() : string | undefined {
|
||||||
const body = core.getInput('body')
|
const body = core.getInput('body')
|
||||||
if (body) {
|
if (body) {
|
||||||
return body
|
return body
|
||||||
@@ -90,14 +83,6 @@ export class CoreInputs implements Inputs {
|
|||||||
return this.name
|
return this.name
|
||||||
}
|
}
|
||||||
|
|
||||||
get discussionCategory(): string | undefined {
|
|
||||||
const category = core.getInput('discussionCategory')
|
|
||||||
if (category) {
|
|
||||||
return category
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
private static get omitName(): boolean {
|
private static get omitName(): boolean {
|
||||||
return core.getInput('omitName') == 'true'
|
return core.getInput('omitName') == 'true'
|
||||||
}
|
}
|
||||||
@@ -171,7 +156,7 @@ export class CoreInputs implements Inputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get updatedReleaseName(): string | undefined {
|
get updatedReleaseName(): string | undefined {
|
||||||
if (CoreInputs.omitName || CoreInputs.omitNameDuringUpdate) return undefined
|
if (CoreInputs.omitName || CoreInputs.omitNameDuringUpdate) return undefined
|
||||||
return this.name
|
return this.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
src/Main.ts
44
src/Main.ts
@@ -1,34 +1,32 @@
|
|||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import {CoreInputs} from './Inputs';
|
import { CoreInputs } from './Inputs';
|
||||||
import {GithubReleases} from './Releases';
|
import { GithubReleases } from './Releases';
|
||||||
import {Action} from './Action';
|
import { Action } from './Action';
|
||||||
import {GithubArtifactUploader} from './ArtifactUploader';
|
import { GithubArtifactUploader } from './ArtifactUploader';
|
||||||
import {FileArtifactGlobber} from './ArtifactGlobber';
|
import { FileArtifactGlobber } from './ArtifactGlobber';
|
||||||
import {GithubError} from './GithubError';
|
import { ErrorMessage } from './ErrorMessage';
|
||||||
import {CoreOutputs} from "./Outputs";
|
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
const action = createAction()
|
const action = createAction()
|
||||||
await action.perform()
|
await action.perform()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const githubError = new GithubError(error)
|
const errorMessage = new ErrorMessage(error)
|
||||||
core.setFailed(githubError.toString());
|
core.setFailed(errorMessage.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAction(): Action {
|
function createAction(): Action {
|
||||||
const token = core.getInput('token')
|
const token = core.getInput('token')
|
||||||
const context = github.context
|
const context = github.context
|
||||||
const git = github.getOctokit(token)
|
const git = github.getOctokit(token)
|
||||||
const globber = new FileArtifactGlobber()
|
const globber = new FileArtifactGlobber()
|
||||||
|
|
||||||
const inputs = new CoreInputs(globber, context)
|
const inputs = new CoreInputs(globber, context)
|
||||||
const outputs = new CoreOutputs()
|
const releases = new GithubReleases(inputs, git)
|
||||||
const releases = new GithubReleases(inputs, git)
|
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts)
|
||||||
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts, inputs.artifactErrorsFailBuild)
|
return new Action(inputs, releases, uploader)
|
||||||
return new Action(inputs, outputs, releases, uploader)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import * as core from '@actions/core';
|
|
||||||
import {ReleaseData} from "./Releases";
|
|
||||||
|
|
||||||
export interface Outputs {
|
|
||||||
applyReleaseData(releaseData: ReleaseData): void
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,23 +6,15 @@ import {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"]
|
||||||
export type ListReleasesResponse = RestEndpointMethodTypes["repos"]["listReleases"]["response"]
|
export type ListReleasesResponse = RestEndpointMethodTypes["repos"]["listReleases"]["response"]
|
||||||
export type ListReleaseAssetsResponseData = RestEndpointMethodTypes["repos"]["listReleaseAssets"]["response"]["data"]
|
export type ListReleaseAssetsResponse = RestEndpointMethodTypes["repos"]["listReleaseAssets"]["response"]
|
||||||
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 ReleaseData = {
|
|
||||||
id: number
|
|
||||||
html_url: string
|
|
||||||
upload_url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Releases {
|
export interface Releases {
|
||||||
create(
|
create(
|
||||||
tag: string,
|
tag: string,
|
||||||
body?: string,
|
body?: string,
|
||||||
commitHash?: string,
|
commitHash?: string,
|
||||||
discussionCategory?: string,
|
|
||||||
draft?: boolean,
|
draft?: boolean,
|
||||||
name?: string,
|
name?: string,
|
||||||
prerelease?: boolean
|
prerelease?: boolean
|
||||||
@@ -32,7 +24,7 @@ export interface Releases {
|
|||||||
|
|
||||||
getByTag(tag: string): Promise<ReleaseByTagResponse>
|
getByTag(tag: string): Promise<ReleaseByTagResponse>
|
||||||
|
|
||||||
listArtifactsForRelease(releaseId: number): Promise<ListReleaseAssetsResponseData>
|
listArtifactsForRelease(releaseId: number): Promise<ListReleaseAssetsResponse>
|
||||||
|
|
||||||
listReleases(): Promise<ListReleasesResponse>
|
listReleases(): Promise<ListReleasesResponse>
|
||||||
|
|
||||||
@@ -41,7 +33,6 @@ export interface Releases {
|
|||||||
tag: string,
|
tag: string,
|
||||||
body?: string,
|
body?: string,
|
||||||
commitHash?: string,
|
commitHash?: string,
|
||||||
discussionCategory?: string,
|
|
||||||
draft?: boolean,
|
draft?: boolean,
|
||||||
name?: string,
|
name?: string,
|
||||||
prerelease?: boolean
|
prerelease?: boolean
|
||||||
@@ -70,7 +61,6 @@ export class GithubReleases implements Releases {
|
|||||||
tag: string,
|
tag: string,
|
||||||
body?: string,
|
body?: string,
|
||||||
commitHash?: string,
|
commitHash?: string,
|
||||||
discussionCategory?: string,
|
|
||||||
draft?: boolean,
|
draft?: boolean,
|
||||||
name?: string,
|
name?: string,
|
||||||
prerelease?: boolean
|
prerelease?: boolean
|
||||||
@@ -79,7 +69,6 @@ export class GithubReleases implements Releases {
|
|||||||
return this.git.repos.createRelease({
|
return this.git.repos.createRelease({
|
||||||
body: body,
|
body: body,
|
||||||
name: name,
|
name: name,
|
||||||
discussion_category_name: discussionCategory,
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
prerelease: prerelease,
|
prerelease: prerelease,
|
||||||
@@ -109,8 +98,8 @@ export class GithubReleases implements Releases {
|
|||||||
|
|
||||||
async listArtifactsForRelease(
|
async listArtifactsForRelease(
|
||||||
releaseId: number
|
releaseId: number
|
||||||
): Promise<ListReleaseAssetsResponseData> {
|
): Promise<ListReleaseAssetsResponse> {
|
||||||
return this.git.paginate(this.git.repos.listReleaseAssets, {
|
return this.git.repos.listReleaseAssets({
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
release_id: releaseId,
|
release_id: releaseId,
|
||||||
repo: this.inputs.repo
|
repo: this.inputs.repo
|
||||||
@@ -129,7 +118,6 @@ export class GithubReleases implements Releases {
|
|||||||
tag: string,
|
tag: string,
|
||||||
body?: string,
|
body?: string,
|
||||||
commitHash?: string,
|
commitHash?: string,
|
||||||
discussionCategory?: string,
|
|
||||||
draft?: boolean,
|
draft?: boolean,
|
||||||
name?: string,
|
name?: string,
|
||||||
prerelease?: boolean
|
prerelease?: boolean
|
||||||
@@ -139,7 +127,6 @@ export class GithubReleases implements Releases {
|
|||||||
release_id: id,
|
release_id: id,
|
||||||
body: body,
|
body: body,
|
||||||
name: name,
|
name: name,
|
||||||
discussion_category_name: discussionCategory,
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
owner: this.inputs.owner,
|
owner: this.inputs.owner,
|
||||||
prerelease: prerelease,
|
prerelease: prerelease,
|
||||||
|
|||||||
25
yarn.lock
25
yarn.lock
@@ -656,7 +656,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
"@types/jest@^26.0.20":
|
"@types/jest@26.x", "@types/jest@^26.0.20":
|
||||||
version "26.0.20"
|
version "26.0.20"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307"
|
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307"
|
||||||
integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==
|
integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==
|
||||||
@@ -1695,9 +1695,9 @@ has@^1.0.3:
|
|||||||
function-bind "^1.1.1"
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
hosted-git-info@^2.1.4:
|
hosted-git-info@^2.1.4:
|
||||||
version "2.8.9"
|
version "2.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
||||||
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
|
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
|
||||||
|
|
||||||
html-encoding-sniffer@^2.0.1:
|
html-encoding-sniffer@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
@@ -2375,7 +2375,7 @@ jest-worker@^26.6.2:
|
|||||||
merge-stream "^2.0.0"
|
merge-stream "^2.0.0"
|
||||||
supports-color "^7.0.0"
|
supports-color "^7.0.0"
|
||||||
|
|
||||||
jest@^26.6.3:
|
jest@^26.1.0:
|
||||||
version "26.6.3"
|
version "26.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef"
|
resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef"
|
||||||
integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==
|
integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==
|
||||||
@@ -2536,9 +2536,9 @@ lodash.sortby@^4.7.0:
|
|||||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||||
|
|
||||||
lodash@4.x, lodash@^4.17.19:
|
lodash@4.x, lodash@^4.17.19:
|
||||||
version "4.17.21"
|
version "4.17.20"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
||||||
|
|
||||||
lru-cache@^6.0.0:
|
lru-cache@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
@@ -3517,11 +3517,12 @@ tr46@^2.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.1"
|
punycode "^2.1.1"
|
||||||
|
|
||||||
ts-jest@^26.5.6:
|
ts-jest@^26.5.1:
|
||||||
version "26.5.6"
|
version "26.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35"
|
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.1.tgz#4d53ee4481552f57c1624f0bd3425c8b17996150"
|
||||||
integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==
|
integrity sha512-G7Rmo3OJMvlqE79amJX8VJKDiRcd7/r61wh9fnvvG8cAjhA9edklGw/dCxRSQmfZ/z8NDums5srSVgwZos1qfg==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@types/jest" "26.x"
|
||||||
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"
|
||||||
|
|||||||
Reference in New Issue
Block a user