7 Commits

Author SHA1 Message Date
Nick Cipollo
880be3d0a7 Prepare 1.8.6 release
Some checks failed
Test / check_pr (push) Has been cancelled
2021-05-24 11:25:03 -04:00
Nick Cipollo
d1125b4510 Fix typescript build 2021-05-24 11:23:05 -04:00
Nick Cipollo
15abc13cc4 Fixes #55 Add artifact validation which check to ensure it's not a directory 2021-05-24 11:21:34 -04:00
Nick Cipollo
616708020f Fixes #50 Add plugin outputs which contain release information. 2021-05-12 11:36:59 -04:00
dependabot[bot]
085dc21232 Bump hosted-git-info from 2.8.8 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-10 19:11:16 -04:00
Nick Cipollo
06fefc702f Bump jest 2021-05-10 19:10:49 -04:00
dependabot[bot]
a84d04e910 Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-10 19:05:50 -04:00
21 changed files with 398 additions and 73 deletions

View File

@@ -25,6 +25,11 @@ 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:

View File

@@ -3,7 +3,9 @@ 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()
@@ -48,6 +50,7 @@ describe("Action", () => {
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease) expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, 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 () => {
@@ -59,6 +62,7 @@ describe("Action", () => {
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease) expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, 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 () => {
@@ -75,6 +79,7 @@ describe("Action", () => {
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease) expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease)
expect(uploadMock).toBeCalledWith(artifacts, releaseId, url) expect(uploadMock).toBeCalledWith(artifacts, releaseId, url)
assertOutputApplied()
}) })
@@ -85,6 +90,7 @@ describe("Action", () => {
expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, draft, createName, prerelease) expect(createMock).toBeCalledWith(tag, createBody, commit, discussionCategory, 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 () => {
@@ -192,7 +198,7 @@ describe("Action", () => {
prerelease 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 () => {
@@ -211,7 +217,7 @@ describe("Action", () => {
prerelease prerelease
) )
expect(uploadMock).not.toBeCalled() expect(uploadMock).not.toBeCalled()
assertOutputApplied()
}) })
it('updates release then uploads artifact', async () => { it('updates release then uploads artifact', async () => {
@@ -230,9 +236,13 @@ describe("Action", () => {
prerelease 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[]
if (hasArtifact) { if (hasArtifact) {
@@ -294,6 +304,11 @@ 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
@@ -301,9 +316,10 @@ 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, releases, uploader) return new Action(inputs, outputs, releases, uploader)
} }
}) })

View File

@@ -13,6 +13,18 @@ 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()

View File

@@ -0,0 +1,60 @@
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()
})
})

View File

@@ -1,10 +1,11 @@
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} from "../src/Releases"; import {GithubReleases, ReleaseData} 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
@@ -17,13 +18,14 @@ 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, releases,
inputs.replacesArtifacts, inputs.replacesArtifacts,
inputs.artifactErrorsFailBuild, inputs.artifactErrorsFailBuild,
) )
action = new Action(inputs, releases, uploader) action = new Action(inputs, outputs, releases, uploader)
}) })
it('Performs action', async () => { it('Performs action', async () => {
@@ -54,10 +56,21 @@ describe.skip('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/test.txt,blarg.tx, ${artifactPath}` const artifactString = `~/Desktop,~/Desktop/test.txt,blarg.tx, ${artifactPath}`
return globber.globArtifactString(artifactString, "raw", false) return globber.globArtifactString(artifactString, "raw", false)
} }

29
__tests__/Outputs.test.ts Normal file
View File

@@ -0,0 +1,29 @@
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)
})
})

View File

@@ -87,6 +87,13 @@ 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'

View File

@@ -12,20 +12,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.Action = void 0; exports.Action = void 0;
const GithubError_1 = require("./GithubError"); const GithubError_1 = require("./GithubError");
class Action { class Action {
constructor(inputs, releases, uploader) { constructor(inputs, outputs, 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 releaseId = releaseResponse.data.id; const releaseData = releaseResponse.data;
const uploadUrl = releaseResponse.data.upload_url; const releaseId = releaseData.id;
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() {

View File

@@ -27,28 +27,34 @@ 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, throwsWhenNoFiles) { globArtifactString(artifact, contentType, errorsFailBuild) {
return artifact.split(',') return artifact.split(',')
.map(path => FileArtifactGlobber.expandPath(path)) .map(path => FileArtifactGlobber.expandPath(path))
.map(pattern => this.globPattern(pattern, throwsWhenNoFiles)) .map(pattern => this.globPattern(pattern, errorsFailBuild))
.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, throwsWhenNoFiles) { globPattern(pattern, errorsFailBuild) {
const paths = this.globber.glob(pattern); const paths = this.globber.glob(pattern);
if (paths.length == 0) { if (paths.length == 0) {
if (throwsWhenNoFiles) { if (errorsFailBuild) {
FileArtifactGlobber.throwGlobError(pattern); FileArtifactGlobber.throwGlobError(pattern);
} }
else { else {
FileArtifactGlobber.reportGlobWarning(pattern); FileArtifactGlobber.reportGlobWarning(pattern);
} }
} }
return paths; return [pattern, 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`);

View File

@@ -0,0 +1,58 @@
"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;

View File

@@ -36,6 +36,7 @@ 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 GithubError_1 = require("./GithubError");
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 {
@@ -54,8 +55,9 @@ 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, inputs.artifactErrorsFailBuild);
return new Action_1.Action(inputs, releases, uploader); return new Action_1.Action(inputs, outputs, releases, uploader);
} }
run(); run();

31
lib/Outputs.js Normal file
View File

@@ -0,0 +1,31 @@
"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
node_modules/.yarn-integrity generated vendored
View File

@@ -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.1.0", "jest@^26.6.3",
"ts-jest@^26.5.1", "ts-jest@^26.5.6",
"typescript@^4.1.4", "typescript@^4.1.4",
"untildify@^4.0.0" "untildify@^4.0.0"
], ],
@@ -112,7 +112,6 @@
"@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",
@@ -286,7 +285,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.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488", "hosted-git-info@^2.1.4": "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9",
"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",
@@ -368,7 +367,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.1.0": "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef", "jest@^26.6.3": "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",
@@ -394,8 +393,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.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52", "lodash@4.x": "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", "lodash@^4.17.19": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c",
"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",
@@ -568,7 +567,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.1": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.1.tgz#4d53ee4481552f57c1624f0bd3425c8b17996150", "ts-jest@^26.5.6": "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35",
"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",

View File

@@ -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.1.0", "jest": "^26.6.3",
"jest-circus": "^26.6.3", "jest-circus": "^26.6.3",
"ts-jest": "^26.5.1", "ts-jest": "^26.5.6",
"typescript": "^4.1.4" "typescript": "^4.1.4"
} }
} }

View File

@@ -1,31 +1,43 @@
import {Inputs} from "./Inputs"; import {Inputs} from "./Inputs";
import {CreateReleaseResponse, ReleaseByTagResponse, Releases, UpdateReleaseResponse} from "./Releases"; import {
CreateOrUpdateReleaseResponse,
CreateReleaseResponse,
ReleaseByTagResponse,
Releases,
UpdateReleaseResponse
} from "./Releases";
import {ArtifactUploader} from "./ArtifactUploader"; import {ArtifactUploader} from "./ArtifactUploader";
import {GithubError} from "./GithubError"; import {GithubError} from "./GithubError";
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, releases: Releases, uploader: ArtifactUploader) { constructor(inputs: Inputs, outputs: Outputs, 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 releaseId = releaseResponse.data.id const releaseData = releaseResponse.data
const uploadUrl = releaseResponse.data.upload_url const releaseId = releaseData.id
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<CreateReleaseResponse | UpdateReleaseResponse> { private async createOrUpdateRelease(): Promise<CreateOrUpdateReleaseResponse> {
if (this.inputs.allowUpdates) { if (this.inputs.allowUpdates) {
let getResponse: ReleaseByTagResponse let getResponse: ReleaseByTagResponse
try { try {
@@ -39,8 +51,8 @@ export class Action {
return await this.createRelease() return await this.createRelease()
} }
} }
private async checkForMissingReleaseError(error: Error) : Promise<CreateReleaseResponse | UpdateReleaseResponse> { private async checkForMissingReleaseError(error: Error): Promise<CreateOrUpdateReleaseResponse> {
if (Action.noPublishedRelease(error)) { if (Action.noPublishedRelease(error)) {
return await this.updateDraftOrCreateRelease() return await this.updateDraftOrCreateRelease()
} else { } else {

View File

@@ -2,9 +2,10 @@ 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, throwsWhenNoFiles: boolean): Artifact[] globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[]
} }
export class FileArtifactGlobber implements ArtifactGlobber { export class FileArtifactGlobber implements ArtifactGlobber {
@@ -14,24 +15,30 @@ export class FileArtifactGlobber implements ArtifactGlobber {
this.globber = globber this.globber = globber
} }
globArtifactString(artifact: string, contentType: string, throwsWhenNoFiles: boolean): Artifact[] { globArtifactString(artifact: string, contentType: string, errorsFailBuild: boolean): Artifact[] {
return artifact.split(',') return artifact.split(',')
.map(path => FileArtifactGlobber.expandPath(path)) .map(path => FileArtifactGlobber.expandPath(path))
.map(pattern => this.globPattern(pattern, throwsWhenNoFiles)) .map(pattern => this.globPattern(pattern, errorsFailBuild))
.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, throwsWhenNoFiles: boolean): string[] { private globPattern(pattern: string, errorsFailBuild: boolean): [string, string[]] {
const paths = this.globber.glob(pattern) const paths = this.globber.glob(pattern)
if (paths.length == 0) { if (paths.length == 0) {
if (throwsWhenNoFiles) { if (errorsFailBuild) {
FileArtifactGlobber.throwGlobError(pattern) FileArtifactGlobber.throwGlobError(pattern)
} else { } else {
FileArtifactGlobber.reportGlobWarning(pattern) FileArtifactGlobber.reportGlobWarning(pattern)
} }
} }
return paths return [pattern, 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) {

View File

@@ -0,0 +1,43 @@
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)
}
}
}

View File

@@ -1,32 +1,34 @@
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 {GithubError} from './GithubError';
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 githubError = new GithubError(error)
core.setFailed(githubError.toString()); core.setFailed(githubError.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 releases = new GithubReleases(inputs, git) const outputs = new CoreOutputs()
const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts, inputs.artifactErrorsFailBuild) const releases = new GithubReleases(inputs, git)
return new Action(inputs, releases, uploader) const uploader = new GithubArtifactUploader(releases, inputs.replacesArtifacts, inputs.artifactErrorsFailBuild)
return new Action(inputs, outputs, releases, uploader)
} }
run(); run();

14
src/Outputs.ts Normal file
View File

@@ -0,0 +1,14 @@
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)
}
}

View File

@@ -9,6 +9,13 @@ export type ListReleasesResponse = RestEndpointMethodTypes["repos"]["listRelease
export type ListReleaseAssetsResponseData = RestEndpointMethodTypes["repos"]["listReleaseAssets"]["response"]["data"] export type ListReleaseAssetsResponseData = RestEndpointMethodTypes["repos"]["listReleaseAssets"]["response"]["data"]
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(

View File

@@ -656,7 +656,7 @@
dependencies: dependencies:
"@types/istanbul-lib-report" "*" "@types/istanbul-lib-report" "*"
"@types/jest@26.x", "@types/jest@^26.0.20": "@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.8" version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
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.1.0: jest@^26.6.3:
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.20" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
lru-cache@^6.0.0: lru-cache@^6.0.0:
version "6.0.0" version "6.0.0"
@@ -3517,12 +3517,11 @@ tr46@^2.0.2:
dependencies: dependencies:
punycode "^2.1.1" punycode "^2.1.1"
ts-jest@^26.5.1: ts-jest@^26.5.6:
version "26.5.1" version "26.5.6"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.1.tgz#4d53ee4481552f57c1624f0bd3425c8b17996150" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35"
integrity sha512-G7Rmo3OJMvlqE79amJX8VJKDiRcd7/r61wh9fnvvG8cAjhA9edklGw/dCxRSQmfZ/z8NDums5srSVgwZos1qfg== integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==
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"