Add and configure ESLint and update configuration for Prettier (#26)

* Add ESLint and Prettier

* Rebuild action

* Update package.json

* Update licenses

* Fix review points
This commit is contained in:
Ivan 2023-03-08 10:50:45 +02:00 committed by GitHub
parent 87579b14ff
commit 9169aa7609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 2490 additions and 439 deletions

6
.eslintignore Normal file
View File

@ -0,0 +1,6 @@
# Ignore list
/*
# Do not ignore these folders:
!__tests__/
!src/

49
.eslintrc.js Normal file
View File

@ -0,0 +1,49 @@
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:eslint-plugin-jest/recommended',
'eslint-config-prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin-jest'],
rules: {
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-ignore': 'allow-with-description'
}
],
'no-console': 'error',
'yoda': 'error',
'prefer-const': [
'error',
{
destructuring: 'all'
}
],
'no-control-regex': 'off',
'no-constant-condition': ['error', {checkLoops: false}]
},
overrides: [
{
files: ['**/*{test,spec}.ts'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'jest/no-standalone-expect': 'off',
'jest/no-conditional-expect': 'off',
'no-console': 'off',
}
}
],
env: {
node: true,
es6: true,
'jest/globals': true
}
};

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
* text=auto eol=lf
.licenses/** -diff linguist-generated=true

Binary file not shown.

7
.prettierignore Normal file
View File

@ -0,0 +1,7 @@
# Ignore list
/*
# Do not ignore these folders:
!__tests__/
!.github/
!src/

10
.prettierrc.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
trailingComma: 'none',
bracketSpacing: false,
arrowParens: 'avoid'
};

View File

@ -1,35 +1,39 @@
import * as github from "@actions/github"; import * as github from '@actions/github';
import * as apiUtils from "../src/api-utils"; import * as apiUtils from '../src/api-utils';
const prereleaseData = require("./data/pre-release.json"); import prereleaseData from './data/pre-release.json';
const releaseData = require("./data/release.json"); import releaseData from './data/release.json';
const token = "faketoken"; const token = 'faketoken';
const octokitClient = github.getOctokit(token); const octokitClient = github.getOctokit(token);
let getReleaseSpy: jest.SpyInstance; let getReleaseSpy: jest.SpyInstance;
process.env.GITHUB_REPOSITORY = "test/repository"; process.env.GITHUB_REPOSITORY = 'test/repository';
describe("validateIfReleaseIsPublished", () => { describe('validateIfReleaseIsPublished', () => {
beforeEach(() => { beforeEach(() => {
getReleaseSpy = jest.spyOn(octokitClient.repos, "getReleaseByTag"); getReleaseSpy = jest.spyOn(octokitClient.repos, 'getReleaseByTag');
}); });
it("throw if release is marked as pre-release", async () => { it('throw if release is marked as pre-release', async () => {
getReleaseSpy.mockReturnValue(prereleaseData); getReleaseSpy.mockReturnValue(prereleaseData);
expect.assertions(1); expect.assertions(1);
await expect(apiUtils.validateIfReleaseIsPublished("v1.0.0", octokitClient)).rejects.toThrowError( await expect(
apiUtils.validateIfReleaseIsPublished('v1.0.0', octokitClient)
).rejects.toThrow(
"The 'v1.0.0' release is marked as pre-release. Updating tags for pre-release is not supported" "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 () => { it('validate that release is published', async () => {
getReleaseSpy.mockReturnValue(releaseData); getReleaseSpy.mockReturnValue(releaseData);
expect.assertions(1); expect.assertions(1);
await expect(apiUtils.validateIfReleaseIsPublished("v1.1.0", octokitClient)).resolves.not.toThrow(); await expect(
apiUtils.validateIfReleaseIsPublished('v1.1.0', octokitClient)
).resolves.not.toThrow();
}); });
afterEach(() => { afterEach(() => {

View File

@ -1,69 +1,93 @@
import * as versionUtils from "../src/version-utils"; import * as versionUtils from '../src/version-utils';
import stableSemver from './data/stable-semver.json';
import stableBuildSemver from './data/stable-build-semver.json';
import prereleaseSemver from './data/prerelease-semver.json';
import prereleaseBuildSemver from './data/prerelease-build-semver.json';
describe("isStableSemverVersion", () => { describe('isStableSemverVersion', () => {
it("validate if a version is stable", () => { it('validate if a version is stable', () => {
const semverVersion = require("./data/stable-semver.json"); expect(
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy(); versionUtils.isStableSemverVersion(stableSemver as any)
).toBeTruthy();
}); });
it("validate if a version with build metadata is stable", () => { it('validate if a version with build metadata is stable', () => {
const semverVersion = require("./data/stable-build-semver.json"); expect(
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeTruthy(); versionUtils.isStableSemverVersion(stableBuildSemver as any)
).toBeTruthy();
}); });
it("validate if a pre-release version is not stable", () => { it('validate if a pre-release version is not stable', () => {
const semverVersion = require("./data/prerelease-semver.json"); expect(
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy(); versionUtils.isStableSemverVersion(prereleaseSemver as any)
).toBeFalsy();
}); });
it("validate if a pre-release version with build metadata is not stable", () => { it('validate if a pre-release version with build metadata is not stable', () => {
const semverVersion = require("./data/prerelease-build-semver.json"); expect(
expect(versionUtils.isStableSemverVersion(semverVersion)).toBeFalsy(); versionUtils.isStableSemverVersion(prereleaseBuildSemver as any)
).toBeFalsy();
}); });
}); });
describe("validateSemverVersionFromTag", () => { describe('validateSemverVersionFromTag', () => {
it("validate a tag containing an valid semantic version", () => { it('validate a tag containing a valid semantic version', () => {
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0")).not.toThrow(); expect(() =>
versionUtils.validateSemverVersionFromTag('1.0.0')
).not.toThrow();
}); });
it("validate a tag containing an valid semantic version with 'v' prefix", () => { it("validate a tag containing a valid semantic version with 'v' prefix", () => {
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0")).not.toThrow(); expect(() =>
versionUtils.validateSemverVersionFromTag('v1.0.0')
).not.toThrow();
}); });
it("validate a tag containing an valid semantic version with build metadata", () => { it('validate a tag containing a valid semantic version with build metadata', () => {
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0+20130313144700")).not.toThrow(); expect(() =>
versionUtils.validateSemverVersionFromTag('v1.0.0+20130313144700')
).not.toThrow();
}); });
it("throw when a tag contains an invalid semantic version", () => { it('throw when a tag contains an invalid semantic version', () => {
expect(() => versionUtils.validateSemverVersionFromTag("1.0.0invalid")).toThrowError( expect(() =>
versionUtils.validateSemverVersionFromTag('1.0.0invalid')
).toThrow(
"The '1.0.0invalid' doesn't satisfy semantic versioning specification" "The '1.0.0invalid' doesn't satisfy semantic versioning specification"
); );
}); });
it("throw when a tag contains an valid unstable semantic version", () => { it('throw when a tag contains a valid unstable semantic version', () => {
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1")).toThrowError( expect(() =>
"It is not allowed to specify pre-release version to update the major tag" versionUtils.validateSemverVersionFromTag('v1.0.0-beta.1')
).toThrow(
'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", () => { it('throw when a tag contains a valid unstable semantic version with build metadata', () => {
expect(() => versionUtils.validateSemverVersionFromTag("v1.0.0-beta.1+20130313144700")).toThrowError( expect(() =>
"It is not allowed to specify pre-release version to update the major tag" versionUtils.validateSemverVersionFromTag('v1.0.0-beta.1+20130313144700')
).toThrow(
'It is not allowed to specify pre-release version to update the major tag'
); );
}); });
}); });
describe("getMajorTagFromFullTag", () => { describe('getMajorTagFromFullTag', () => {
describe("get a valid major tag from full tag", () => { describe('get a valid major tag from full tag', () => {
it.each([ it.each([
["1.0.0", "1"], ['1.0.0', '1'],
["v1.0.0", "v1"], ['v1.0.0', 'v1'],
["v1.0.0-beta.1", "v1"], ['v1.0.0-beta.1', 'v1'],
["v1.0.0+20130313144700", "v1"], ['v1.0.0+20130313144700', 'v1']
] as [string, string][])("%s -> %s", (sourceTag: string, expectedMajorTag: string) => { ] as [string, string][])(
const resultantMajorTag = versionUtils.getMajorTagFromFullTag(sourceTag); '%s -> %s',
(sourceTag: string, expectedMajorTag: string) => {
const resultantMajorTag =
versionUtils.getMajorTagFromFullTag(sourceTag);
expect(resultantMajorTag).toBe(expectedMajorTag); expect(resultantMajorTag).toBe(expectedMajorTag);
}); }
);
}); });
}); });

21
dist/index.js vendored
View File

@ -58,7 +58,7 @@ async function validateIfReleaseIsPublished(tag, octokitClient) {
try { try {
const { data: foundRelease } = await octokitClient.repos.getReleaseByTag({ const { data: foundRelease } = await octokitClient.repos.getReleaseByTag({
...github_1.context.repo, ...github_1.context.repo,
tag, tag
}); });
if (foundRelease.prerelease) { if (foundRelease.prerelease) {
throw new Error(`The '${foundRelease.name}' release is marked as pre-release. Updating tags for pre-release is not supported`); throw new Error(`The '${foundRelease.name}' release is marked as pre-release. Updating tags for pre-release is not supported`);
@ -157,7 +157,6 @@ async function run() {
await reportStatusToSlack(slackMessage); await reportStatusToSlack(slackMessage);
} }
} }
;
async function reportStatusToSlack(message) { async function reportStatusToSlack(message) {
const slackWebhook = core.getInput('slack-webhook'); const slackWebhook = core.getInput('slack-webhook');
if (slackWebhook) { if (slackWebhook) {
@ -9593,7 +9592,7 @@ class SemVer {
if (identifier) { if (identifier) {
// 1.2.0-beta.1 bumps to 1.2.0-beta.2, // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
// 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
if (this.prerelease[0] === identifier) { if (compareIdentifiers(this.prerelease[0], identifier) === 0) {
if (isNaN(this.prerelease[1])) { if (isNaN(this.prerelease[1])) {
this.prerelease = [identifier, 0] this.prerelease = [identifier, 0]
} }
@ -9675,7 +9674,7 @@ module.exports = {
SEMVER_SPEC_VERSION, SEMVER_SPEC_VERSION,
MAX_LENGTH, MAX_LENGTH,
MAX_SAFE_INTEGER, MAX_SAFE_INTEGER,
MAX_SAFE_COMPONENT_LENGTH MAX_SAFE_COMPONENT_LENGTH,
} }
@ -9721,7 +9720,7 @@ const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)
module.exports = { module.exports = {
compareIdentifiers, compareIdentifiers,
rcompareIdentifiers rcompareIdentifiers,
} }
@ -9736,9 +9735,9 @@ const opts = ['includePrerelease', 'loose', 'rtl']
const parseOptions = options => const parseOptions = options =>
!options ? {} !options ? {}
: typeof options !== 'object' ? { loose: true } : typeof options !== 'object' ? { loose: true }
: opts.filter(k => options[k]).reduce((options, k) => { : opts.filter(k => options[k]).reduce((o, k) => {
options[k] = true o[k] = true
return options return o
}, {}) }, {})
module.exports = parseOptions module.exports = parseOptions
@ -9760,7 +9759,7 @@ let R = 0
const createToken = (name, value, isGlobal) => { const createToken = (name, value, isGlobal) => {
const index = R++ const index = R++
debug(index, value) debug(name, index, value)
t[name] = index t[name] = index
src[index] = value src[index] = value
re[index] = new RegExp(value, isGlobal ? 'g' : undefined) re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
@ -9928,8 +9927,8 @@ createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
// Star ranges basically just allow anything at all. // Star ranges basically just allow anything at all.
createToken('STAR', '(<|>)?=?\\s*\\*') createToken('STAR', '(<|>)?=?\\s*\\*')
// >=0.0.0 is like a star // >=0.0.0 is like a star
createToken('GTE0', '^\\s*>=\\s*0\.0\.0\\s*$') createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')
createToken('GTE0PRE', '^\\s*>=\\s*0\.0\.0-0\\s*$') createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
/***/ }), /***/ }),

1979
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,10 @@
"scripts": { "scripts": {
"build": "tsc && ncc build", "build": "tsc && ncc build",
"test": "jest", "test": "jest",
"format-check": "echo \"Fake command that does nothing. It is used in reusable workflows\"", "format": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write **/*.{ts,yml,yaml}",
"lint": "echo \"Fake command that does nothing. It is used in reusable workflows\"" "format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check **/*.{ts,yml,yaml}",
"lint": "eslint --config ./.eslintrc.js **/*.ts",
"lint:fix": "eslint --config ./.eslintrc.js **/*.ts --fix"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -25,16 +27,22 @@
"homepage": "https://github.com/actions/publish-action#readme", "homepage": "https://github.com/actions/publish-action#readme",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.7", "@actions/core": "^1.2.7",
"@actions/http-client": "^1.0.11",
"@actions/github": "^4.0.0", "@actions/github": "^4.0.0",
"@actions/http-client": "^1.0.11",
"semver": "^7.3.5" "semver": "^7.3.5"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^27.0.2", "@types/jest": "^27.0.2",
"@types/semver": "^7.3.6", "@types/semver": "^7.3.6",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"@vercel/ncc": "^0.28.5", "@vercel/ncc": "^0.28.5",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-jest": "^27.2.1",
"jest": "^27.2.5", "jest": "^27.2.5",
"jest-circus": "^27.2.5", "jest-circus": "^27.2.5",
"prettier": "^2.8.4",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^4.2.4" "typescript": "^4.2.4"
} }

View File

@ -42,9 +42,7 @@ async function getTagSHA(
): Promise<string> { ): Promise<string> {
const foundTag = await findTag(tag, octokitClient); const foundTag = await findTag(tag, octokitClient);
if (!foundTag) { if (!foundTag) {
throw new Error( throw new Error(`The '${tag}' tag does not exist in the remote repository`);
`The '${tag}' tag does not exist in the remote repository`
);
} }
return foundTag.object.sha; return foundTag.object.sha;
@ -57,7 +55,7 @@ export async function validateIfReleaseIsPublished(
try { try {
const {data: foundRelease} = await octokitClient.repos.getReleaseByTag({ const {data: foundRelease} = await octokitClient.repos.getReleaseByTag({
...context.repo, ...context.repo,
tag, tag
}); });
if (foundRelease.prerelease) { if (foundRelease.prerelease) {
@ -67,9 +65,7 @@ export async function validateIfReleaseIsPublished(
} }
} catch (err) { } catch (err) {
if (err.status === 404) { if (err.status === 404) {
throw new Error( throw new Error(`No GitHub release found for the ${tag} tag`);
`No GitHub release found for the ${tag} tag`
);
} else { } else {
throw new Error( throw new Error(
`Retrieving releases failed with the following error: ${err}` `Retrieving releases failed with the following error: ${err}`
@ -88,7 +84,9 @@ export async function updateTag(
const refName = `tags/${targetTag}`; const refName = `tags/${targetTag}`;
if (foundTargetTag) { if (foundTargetTag) {
core.info(`Updating the '${targetTag}' tag to point to the '${sourceTag}' tag`); core.info(
`Updating the '${targetTag}' tag to point to the '${sourceTag}' tag`
);
await octokitClient.git.updateRef({ await octokitClient.git.updateRef({
...context.repo, ...context.repo,
@ -107,8 +105,11 @@ export async function updateTag(
} }
} }
export async function postMessageToSlack(slackWebhook: string, message: string): Promise<void> { export async function postMessageToSlack(
const jsonData = {text: message} slackWebhook: string,
message: string
): Promise<void> {
const jsonData = {text: message};
const http = new HttpClient(); const http = new HttpClient();
await http.postJson(slackWebhook, jsonData); await http.postJson(slackWebhook, jsonData);
} }

View File

@ -1,8 +1,15 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as github from '@actions/github'; import * as github from '@actions/github';
import {context} from '@actions/github'; import {context} from '@actions/github';
import { updateTag, validateIfReleaseIsPublished, postMessageToSlack } from './api-utils'; import {
import { validateSemverVersionFromTag, getMajorTagFromFullTag } from './version-utils'; updateTag,
validateIfReleaseIsPublished,
postMessageToSlack
} from './api-utils';
import {
validateSemverVersionFromTag,
getMajorTagFromFullTag
} from './version-utils';
async function run(): Promise<void> { async function run(): Promise<void> {
try { try {
@ -18,7 +25,9 @@ async function run(): Promise<void> {
await updateTag(sourceTagName, majorTag, octokitClient); await updateTag(sourceTagName, majorTag, octokitClient);
core.setOutput('major-tag', majorTag); core.setOutput('major-tag', majorTag);
core.info(`The '${majorTag}' major tag now points to the '${sourceTagName}' tag`); core.info(
`The '${majorTag}' major tag now points to the '${sourceTagName}' tag`
);
const slackMessage = `The ${majorTag} tag has been successfully updated for the ${context.repo.repo} action to include changes from ${sourceTagName}`; const slackMessage = `The ${majorTag} tag has been successfully updated for the ${context.repo.repo} action to include changes from ${sourceTagName}`;
await reportStatusToSlack(slackMessage); await reportStatusToSlack(slackMessage);
@ -28,7 +37,7 @@ async function run(): Promise<void> {
const slackMessage = `Failed to update a major tag for the ${context.repo.repo} action`; const slackMessage = `Failed to update a major tag for the ${context.repo.repo} action`;
await reportStatusToSlack(slackMessage); await reportStatusToSlack(slackMessage);
} }
}; }
async function reportStatusToSlack(message: string): Promise<void> { async function reportStatusToSlack(message: string): Promise<void> {
const slackWebhook = core.getInput('slack-webhook'); const slackWebhook = core.getInput('slack-webhook');

View File

@ -2,7 +2,7 @@ import semverParse from 'semver/functions/parse';
import SemVer from 'semver/classes/semver'; import SemVer from 'semver/classes/semver';
export function isStableSemverVersion(version: SemVer): boolean { export function isStableSemverVersion(version: SemVer): boolean {
return version.prerelease.length === 0 return version.prerelease.length === 0;
} }
export function getMajorTagFromFullTag(fullTag: string): string { export function getMajorTagFromFullTag(fullTag: string): string {

View File

@ -5,6 +5,7 @@
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true,
"strict": true, "strict": true,
"noImplicitAny": true, "noImplicitAny": true,