mirror of
https://github.com/actions/publish-action.git
synced 2025-02-24 16:22:31 +00:00
Implement the "publish-action" action
This commit is contained in:
parent
d90d23df2a
commit
d8eb8e53b7
48
.github/workflows/release-new-action-version.yml
vendored
Normal file
48
.github/workflows/release-new-action-version.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: Release new action version
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
TAG_NAME:
|
||||
description: 'Tag name that the major tag will point to'
|
||||
required: true
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
|
||||
jobs:
|
||||
update_tag:
|
||||
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
|
||||
environment:
|
||||
name: releaseNewActionVersion
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Update the ${{ env.TAG_NAME }} tag
|
||||
id: update-major-tag
|
||||
uses: ./
|
||||
with:
|
||||
source-tag: ${{ env.TAG_NAME }}
|
||||
|
||||
- name: Send slack message
|
||||
if: failure()
|
||||
run: |
|
||||
curl `
|
||||
-X POST `
|
||||
-H 'Content-type: application/json' `
|
||||
--data '{\"text\":\"Failed to update a major tag for the ${{ github.repository }} action\"}' `
|
||||
${{ secrets.SLACK }}
|
||||
|
||||
- name: Send slack message
|
||||
if: success()
|
||||
run: |
|
||||
curl `
|
||||
-X POST `
|
||||
-H 'Content-type: application/json' `
|
||||
--data '{\"text\":\"The ${{ steps.update-major-tag.outputs.major-tag }} tag has been successfully updated for the ${{ github.repository }} action to include changes from the ${{ env.TAG_NAME }}\"}' `
|
||||
${{ secrets.SLACK }}
|
27
.github/workflows/test.yml
vendored
Normal file
27
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.JS
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
lib/
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 GitHub, Inc. and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
25
README.md
25
README.md
@ -1 +1,26 @@
|
||||
# publish-action
|
||||
|
||||
**Please note: this action is for internal usage only, we don't track issues or accept any contributions. We also do not recommend it for public or production usage.**
|
||||
|
||||
This action adds reliability to the new action versions publishing and handles the following cases:
|
||||
- Update a major tag (v1, for example) to point to the latest release (v1.2.1, for example).
|
||||
- Create a major tag from the latest released tag if a major tag doesn't exist
|
||||
|
||||
## Status
|
||||
Alpha. Action is under development and internal testing.
|
||||
|
||||
## Usage
|
||||
Action can be triggered on release creation or manually. The actual major tag update will require manual approval.
|
||||
See [release-new-action-version.yml](./.github/workflows/release-new-action-version.yml) for usage example.
|
||||
|
||||
See [action.yml](action.yml) for a complete description of input and output fields.
|
||||
Read more about action versioning notation in [action-versioning.md](https://github.com/actions/toolkit/blob/main/docs/action-versioning.md).
|
||||
|
||||
To roll back a release in case of customer impact, start the workflow manually and specify the previous stable tag.
|
||||
|
||||
## Conributions
|
||||
|
||||
We don't accept contributions until the action is ready for production.
|
||||
|
||||
## License
|
||||
The scripts and documentation in this project are released under the [MIT License](LICENSE).
|
||||
|
39
__tests__/api-utils.test.ts
Normal file
39
__tests__/api-utils.test.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import * as github from "@actions/github";
|
||||
import * as apiUtils from "../src/api-utils";
|
||||
|
||||
const prereleaseData = require("./data/pre-release.json");
|
||||
const releaseData = require("./data/release.json");
|
||||
|
||||
const token = "faketoken";
|
||||
const octokitClient = github.getOctokit(token);
|
||||
|
||||
let getReleaseSpy: jest.SpyInstance;
|
||||
|
||||
process.env.GITHUB_REPOSITORY = "test/repository";
|
||||
|
||||
describe("validateIfReleaseIsPublished", () => {
|
||||
beforeEach(() => {
|
||||
getReleaseSpy = jest.spyOn(octokitClient.repos, "getReleaseByTag");
|
||||
});
|
||||
|
||||
it("throw if release is marked as pre-release", async () => {
|
||||
getReleaseSpy.mockReturnValue(prereleaseData);
|
||||
|
||||
expect.assertions(1);
|
||||
await expect(apiUtils.validateIfReleaseIsPublished("v1.0.0", octokitClient)).rejects.toThrowError(
|
||||
"The 'v1.0.0' release is marked as pre-release. Updating tags for pre-release is not supported"
|
||||
);
|
||||
});
|
||||
|
||||
it("validate that release is published", async () => {
|
||||
getReleaseSpy.mockReturnValue(releaseData);
|
||||
|
||||
expect.assertions(1);
|
||||
await expect(apiUtils.validateIfReleaseIsPublished("v1.1.0", octokitClient)).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
});
|
14
__tests__/data/pre-release.json
Normal file
14
__tests__/data/pre-release.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"data": {
|
||||
"id": 1,
|
||||
"node_id": "MDc6UmVsZWFzZTE=",
|
||||
"tag_name": "v1.0.0",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.0",
|
||||
"body": "Description of the release",
|
||||
"draft": false,
|
||||
"prerelease": true,
|
||||
"created_at": "2013-02-27T19:35:32Z",
|
||||
"published_at": "2013-02-27T19:35:32Z"
|
||||
}
|
||||
}
|
12
__tests__/data/prerelease-build-semver.json
Normal file
12
__tests__/data/prerelease-build-semver.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"options": {},
|
||||
"loose": false,
|
||||
"includePrerelease": false,
|
||||
"raw": "v1.0.0-beta.1+20130313144700",
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0,
|
||||
"prerelease": [ "beta", 1 ],
|
||||
"build": [ "20130313144700" ],
|
||||
"version": "1.0.0-beta.1"
|
||||
}
|
12
__tests__/data/prerelease-semver.json
Normal file
12
__tests__/data/prerelease-semver.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"options": {},
|
||||
"loose": false,
|
||||
"includePrerelease": false,
|
||||
"raw": "v1.0.0-beta.1",
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0,
|
||||
"prerelease": [ "beta", 1 ],
|
||||
"build": [],
|
||||
"version": "1.0.0-beta.1"
|
||||
}
|
14
__tests__/data/release.json
Normal file
14
__tests__/data/release.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"data": {
|
||||
"id": 1,
|
||||
"node_id": "MDc6UmVsZWFzZTE=",
|
||||
"tag_name": "v1.1.0",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.1.0",
|
||||
"body": "Description of the release",
|
||||
"draft": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2013-02-27T19:35:32Z",
|
||||
"published_at": "2013-02-27T19:35:32Z"
|
||||
}
|
||||
}
|
12
__tests__/data/stable-build-semver.json
Normal file
12
__tests__/data/stable-build-semver.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"options": {},
|
||||
"loose": false,
|
||||
"includePrerelease": false,
|
||||
"raw": "1.0.0+20130313144700",
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0,
|
||||
"prerelease": [],
|
||||
"build": [ "20130313144700" ],
|
||||
"version": "1.0.0"
|
||||
}
|
12
__tests__/data/stable-semver.json
Normal file
12
__tests__/data/stable-semver.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"options": {},
|
||||
"loose": false,
|
||||
"includePrerelease": false,
|
||||
"raw": "v1.0.0",
|
||||
"major": 1,
|
||||
"minor": 0,
|
||||
"patch": 0,
|
||||
"prerelease": [],
|
||||
"build": [],
|
||||
"version": "1.0.0"
|
||||
}
|
69
__tests__/version-utils.test.ts
Normal file
69
__tests__/version-utils.test.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import * as versionUtils from "../src/version-utils";
|
||||
|
||||
describe("isStableSemverVersion", () => {
|
||||
it("validate if a version is stable", () => {
|
||||
const semverVersion = require("./data/stable-semver.json");
|
||||
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("validate if a version with build metadata is stable", () => {
|
||||
const semverVersion = require("./data/stable-build-semver.json");
|
||||
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("validate if a pre-release version is not stable", () => {
|
||||
const semverVersion = require("./data/prerelease-semver.json");
|
||||
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("validate if a pre-release version with build metadata is not stable", () => {
|
||||
const semverVersion = require("./data/prerelease-build-semver.json");
|
||||
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateSemverVersionFromTag", () => {
|
||||
it("validate a tag containing an valid semantic version", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0")).not.toThrow();
|
||||
});
|
||||
|
||||
it("validate a tag containing an valid semantic version with 'v' prefix", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0")).not.toThrow();
|
||||
});
|
||||
|
||||
it("validate a tag containing an valid semantic version with build metadata", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0+20130313144700")).not.toThrow();
|
||||
});
|
||||
|
||||
it("throw when a tag contains an invalid semantic version", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0invalid")).toThrowError(
|
||||
"The '1.0.0invalid' doesn't satisfy semantic versioning specification"
|
||||
);
|
||||
});
|
||||
|
||||
it("throw when a tag contains an valid unstable semantic version", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1")).toThrowError(
|
||||
"It is not allowed to specify pre-release version to update the major tag"
|
||||
);
|
||||
});
|
||||
|
||||
it("throw when a tag contains an valid unstable semantic version with build metadata", () => {
|
||||
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1+20130313144700")).toThrowError(
|
||||
"It is not allowed to specify pre-release version to update the major tag"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getMajorTagFromFullTag", () => {
|
||||
describe("get a valid major tag from full tag", () => {
|
||||
it.each([
|
||||
["1.0.0", "1"],
|
||||
["v1.0.0", "v1"],
|
||||
["v1.0.0-beta.1", "v1"],
|
||||
["v1.0.0+20130313144700", "v1"],
|
||||
] as [string, string][])("%s -> %s", (sourceTag: string, expectedMajorTag: string) => {
|
||||
const resultantMajorTag = versionUtils.getMajorTagFromFullTag(sourceTag);
|
||||
expect(resultantMajorTag).toBe(expectedMajorTag);
|
||||
});
|
||||
});
|
||||
});
|
15
action.yml
Normal file
15
action.yml
Normal file
@ -0,0 +1,15 @@
|
||||
name: 'Publish action versions'
|
||||
description: 'Move the major version tag to point to the specified ref'
|
||||
inputs:
|
||||
source-tag:
|
||||
description: 'Tag name that the major tag will point to. Examples: v1.2.3, 1.2.3'
|
||||
required: true
|
||||
token:
|
||||
description: 'Token to get an authenticated Octokit'
|
||||
default: ${{ github.token }}
|
||||
outputs:
|
||||
major-tag:
|
||||
description: 'The major version tag that has been updated (created). Examples: v1, 1'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: 'dist/index.js'
|
6844
dist/index.js
vendored
Normal file
6844
dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
jest.config.js
Normal file
11
jest.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: true
|
||||
}
|
5086
package-lock.json
generated
Normal file
5086
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "publish-action",
|
||||
"version": "1.0.0",
|
||||
"description": "Update the major version tag (v1, v2, etc.) to point to the specified tag",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc && ncc build",
|
||||
"test": "jest"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/publish-action.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions",
|
||||
"publish"
|
||||
],
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/publish-action/issues"
|
||||
},
|
||||
"homepage": "https://github.com/actions/publish-action#readme",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.7",
|
||||
"@actions/github": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/semver": "^7.3.6",
|
||||
"@vercel/ncc": "^0.28.5",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^26.6.3",
|
||||
"semver": "^7.3.5",
|
||||
"ts-jest": "^26.5.6",
|
||||
"typescript": "^4.2.4"
|
||||
}
|
||||
}
|
103
src/api-utils.ts
Normal file
103
src/api-utils.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import * as core from '@actions/core';
|
||||
import { context } from '@actions/github';
|
||||
import { GitHub } from '@actions/github/lib/utils';
|
||||
|
||||
interface GitRef {
|
||||
ref: string;
|
||||
node_id: string;
|
||||
url: string;
|
||||
object: {
|
||||
type: string;
|
||||
sha: string;
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
|
||||
async function findTag(
|
||||
tag: string,
|
||||
octokitClient: InstanceType<typeof GitHub>
|
||||
): Promise<GitRef | null> {
|
||||
try {
|
||||
const { data: foundTag } = await octokitClient.git.getRef({
|
||||
...context.repo,
|
||||
ref: `tags/${tag}`
|
||||
});
|
||||
|
||||
return foundTag;
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
return null;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getTagSHA(
|
||||
tag: string,
|
||||
octokitClient: InstanceType<typeof GitHub>
|
||||
): Promise<string> {
|
||||
const foundTag = await findTag(tag, octokitClient);
|
||||
if (!foundTag) {
|
||||
throw new Error(
|
||||
`The '${tag}' tag does not exist in the remote repository`
|
||||
);
|
||||
}
|
||||
|
||||
return foundTag.object.sha;
|
||||
}
|
||||
|
||||
export async function validateIfReleaseIsPublished(
|
||||
tag: string,
|
||||
octokitClient: InstanceType<typeof GitHub>
|
||||
): Promise<void> {
|
||||
try {
|
||||
const { data: foundRelease } = await octokitClient.repos.getReleaseByTag({
|
||||
...context.repo,
|
||||
tag,
|
||||
});
|
||||
|
||||
if (foundRelease.prerelease){
|
||||
throw new Error(
|
||||
`The '${foundRelease.name}' release is marked as pre-release. Updating tags for pre-release is not supported`
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
throw new Error(
|
||||
`No GitHub release found for the ${tag} tag`
|
||||
);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateTag(
|
||||
sourceTag: string,
|
||||
targetTag: string,
|
||||
octokitClient: InstanceType<typeof GitHub>
|
||||
): Promise<void> {
|
||||
const sourceTagSHA = await getTagSHA(sourceTag, octokitClient);
|
||||
const foundTargetTag = await findTag(targetTag, octokitClient);
|
||||
const refName = `tags/${targetTag}`;
|
||||
|
||||
if (foundTargetTag) {
|
||||
core.info(`Updating the '${targetTag}' tag to point to the '${sourceTag}' tag`);
|
||||
|
||||
await octokitClient.git.updateRef({
|
||||
...context.repo,
|
||||
ref: refName,
|
||||
sha: sourceTagSHA,
|
||||
force: true
|
||||
});
|
||||
} else {
|
||||
core.info(`Creating the '${targetTag}' tag from the '${sourceTag}' tag`);
|
||||
|
||||
await octokitClient.git.createRef({
|
||||
...context.repo,
|
||||
ref: `refs/${refName}`,
|
||||
sha: sourceTagSHA
|
||||
});
|
||||
}
|
||||
}
|
26
src/main.ts
Normal file
26
src/main.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as github from '@actions/github';
|
||||
import { updateTag, validateIfReleaseIsPublished } from './api-utils';
|
||||
import { validateSemverVersionFromTag, getMajorTagFromFullTag } from './version-utils';
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const token = core.getInput('token');
|
||||
const octokitClient = github.getOctokit(token);
|
||||
const sourceTagName = core.getInput('source-tag');
|
||||
|
||||
validateSemverVersionFromTag(sourceTagName);
|
||||
|
||||
await validateIfReleaseIsPublished(sourceTagName, octokitClient);
|
||||
|
||||
const majorTag = getMajorTagFromFullTag(sourceTagName);
|
||||
await updateTag(sourceTagName, majorTag, octokitClient);
|
||||
|
||||
core.setOutput('major-tag', majorTag);
|
||||
core.info(`The '${majorTag}' major tag now points to the '${sourceTagName}' tag`);
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
run();
|
25
src/version-utils.ts
Normal file
25
src/version-utils.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import semverParse from 'semver/functions/parse';
|
||||
import SemVer from 'semver/classes/semver';
|
||||
|
||||
export function isStableSemverVersion(version: SemVer): boolean {
|
||||
return version.prerelease.length === 0
|
||||
}
|
||||
|
||||
export function getMajorTagFromFullTag(fullTag: string): string {
|
||||
return fullTag.split('.')[0];
|
||||
}
|
||||
|
||||
export function validateSemverVersionFromTag(tag: string): void {
|
||||
const semverVersion = semverParse(tag);
|
||||
if (!semverVersion) {
|
||||
throw new Error(
|
||||
`The '${tag}' doesn't satisfy semantic versioning specification`
|
||||
);
|
||||
}
|
||||
|
||||
if (!isStableSemverVersion(semverVersion)) {
|
||||
throw new Error(
|
||||
'It is not allowed to specify pre-release version to update the major tag'
|
||||
);
|
||||
}
|
||||
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2019",
|
||||
"module": "commonjs",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"esModuleInterop": true,
|
||||
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"strictFunctionTypes": true,
|
||||
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user