From 035c5aaa64f001df617d1f31b6d84a3fae2fe1ab Mon Sep 17 00:00:00 2001 From: Kevin de Jong Date: Thu, 7 Dec 2023 12:22:09 +0100 Subject: [PATCH 1/5] chore: update ESLint configuration to validate imports In addition, the configuration has been migrated from `.JSON` to `.XML`, as is the now recommended layout by ESLint --- .eslintrc.json | 59 ---------------------------------- .eslintrc.yml | 82 +++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 69 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + 4 files changed, 152 insertions(+), 59 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 .eslintrc.yml diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index c0393482..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "plugins": ["jest", "@typescript-eslint"], - "extends": ["plugin:github/recommended"], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 9, - "sourceType": "module", - "project": "./tsconfig.json" - }, - "rules": { - "i18n-text/no-en": "off", - "eslint-comments/no-use": "off", - "import/no-namespace": "off", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars":["error", { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "caughtErrorsIgnorePattern": "^_" - }], - "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}], - "@typescript-eslint/no-require-imports": "error", - "@typescript-eslint/array-type": "error", - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/ban-ts-comment": "error", - "camelcase": "off", - "@typescript-eslint/consistent-type-assertions": "error", - "@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}], - "@typescript-eslint/func-call-spacing": ["error", "never"], - "@typescript-eslint/no-array-constructor": "error", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-extraneous-class": "error", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-inferrable-types": "error", - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-non-null-assertion": "warn", - "@typescript-eslint/no-unnecessary-qualifier": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-useless-constructor": "error", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/prefer-for-of": "warn", - "@typescript-eslint/prefer-function-type": "warn", - "@typescript-eslint/prefer-includes": "error", - "@typescript-eslint/prefer-string-starts-ends-with": "error", - "@typescript-eslint/promise-function-async": "error", - "@typescript-eslint/require-array-sort-compare": "error", - "@typescript-eslint/restrict-plus-operands": "error", - "semi": "off", - "@typescript-eslint/semi": ["off", "never"], - "@typescript-eslint/type-annotation-spacing": "error", - "@typescript-eslint/unbound-method": "error" - }, - "env": { - "node": true, - "es6": true, - "jest/globals": true - } -} diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 00000000..51557d4d --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,82 @@ +--- +plugins: + - jest + - "@typescript-eslint" + - import + +extends: + - plugin:github/recommended + - plugin:import/recommended + - plugin:import/typescript + +env: + node: true + es6: true + jest/globals: true + +settings: + import/resolver: + typescript: true + node: true + +parser: "@typescript-eslint/parser" +parserOptions: + ecmaVersion: 9 + sourceType: module + project: "./tsconfig.json" + +rules: + i18n-text/no-en: off + eslint-comments/no-use: off + filenames/match-regex: off + import/no-namespace: off + no-console: off + one-var: off + "@typescript-eslint/no-unused-vars": + - error + - argsIgnorePattern: "^_" + varsIgnorePattern: "^_" + caughtErrorsIgnorePattern: "^_" + no-unused-vars: off + "@typescript-eslint/explicit-member-accessibility": + - error + - accessibility: no-public + "@typescript-eslint/no-require-imports": error + "@typescript-eslint/array-type": error + "@typescript-eslint/await-thenable": error + "@typescript-eslint/ban-ts-comment": error + camelcase: off + "@typescript-eslint/consistent-type-assertions": error + "@typescript-eslint/explicit-function-return-type": + - error + - allowExpressions: true + "@typescript-eslint/func-call-spacing": [error, never] + "@typescript-eslint/no-array-constructor": error + "@typescript-eslint/no-empty-interface": error + "@typescript-eslint/no-explicit-any": error + "@typescript-eslint/no-extraneous-class": error + "@typescript-eslint/no-for-in-array": error + "@typescript-eslint/no-inferrable-types": error + "@typescript-eslint/no-misused-new": error + "@typescript-eslint/no-namespace": error + "@typescript-eslint/no-non-null-assertion": warn + "@typescript-eslint/no-unnecessary-qualifier": error + "@typescript-eslint/no-unnecessary-type-assertion": error + "@typescript-eslint/no-useless-constructor": error + "@typescript-eslint/no-var-requires": error + "@typescript-eslint/prefer-for-of": warn + "@typescript-eslint/prefer-function-type": warn + "@typescript-eslint/prefer-includes": error + "@typescript-eslint/prefer-string-starts-ends-with": error + "@typescript-eslint/promise-function-async": error + "@typescript-eslint/require-array-sort-compare": error + "@typescript-eslint/restrict-plus-operands": error + semi: off + "@typescript-eslint/type-annotation-spacing": error + "@typescript-eslint/unbound-method": error + import/extensions: # see https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/extensions.md + - error + - never + - pattern: + json: ignorePackages + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4a94d00e..1a852c9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "@typescript-eslint/parser": "^5.56.0", "@vercel/ncc": "^0.36.1", "eslint": "^8.36.0", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-github": "^4.6.1", "eslint-plugin-jest": "^27.2.1", "eslint-plugin-prettier": "^5.0.1", @@ -3499,6 +3500,19 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3731,6 +3745,31 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, "node_modules/eslint-module-utils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", @@ -4718,6 +4757,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -7780,6 +7831,15 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve.exports": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", @@ -8378,6 +8438,15 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", diff --git a/package.json b/package.json index dd93b8f4..137530e2 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@typescript-eslint/parser": "^5.56.0", "@vercel/ncc": "^0.36.1", "eslint": "^8.36.0", + "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-github": "^4.6.1", "eslint-plugin-jest": "^27.2.1", "eslint-plugin-prettier": "^5.0.1", From 63d09113b684c3068b6f48d303b13321e3aef59c Mon Sep 17 00:00:00 2001 From: Kevin de Jong Date: Thu, 7 Dec 2023 12:31:07 +0100 Subject: [PATCH 2/5] chore: enable strict type checking --- tsconfig.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 06e0abad..d0d52b2b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,14 @@ { "compilerOptions": { - "target": "es6", + "target": "ES2019", "module": "commonjs", - "rootDir": "./src", + "declaration": true, + "outDir": "./lib", "strict": true, - "noImplicitAny": false, "esModuleInterop": true, - "types": ["node", "jest"] + "stripInternal": true, + "resolveJsonModule": true, }, - "exclude": ["node_modules", "test"] + "include": ["src"], + "exclude": ["node_modules", "test/"] } From 2b643a4868605564f2c19e954f81c9635ebe54ff Mon Sep 17 00:00:00 2001 From: Kevin de Jong Date: Thu, 7 Dec 2023 15:00:25 +0100 Subject: [PATCH 3/5] fix: ensure that unexpected exceptions are no longer caught Originally we would catch all exceptions thrown in the validate, bump, and CLI execution. As a result, the action will ignore certain failures and, in case of `bump`, continue as if nothing went wrong (but also without the associated bump). --- dist/bump/index.js | 1831 +++++++++++++-------------- dist/cli/index.js | 194 ++- dist/validate/index.js | 1759 +++++++++++++------------ package-lock.json | 612 +++++---- package.json | 11 +- src/actions/bump.ts | 15 +- src/actions/entrypoints/bump.ts | 19 + src/actions/entrypoints/validate.ts | 19 + src/actions/validate.ts | 16 +- src/bump.ts | 21 +- src/cli/cli.ts | 10 +- src/cli/utils.ts | 13 +- src/commit.ts | 2 +- src/config.ts | 76 +- src/errors.ts | 2 +- src/github.ts | 36 +- src/interfaces.ts | 7 - src/rules.ts | 11 +- src/semver.ts | 2 +- src/validate.ts | 24 +- test/bump.sdkver.test.ts | 13 +- test/bump.test.ts | 20 +- test/config.test.ts | 27 +- test/rules.test.ts | 2 +- test/validate.test.ts | 8 +- tsconfig.json | 2 - 26 files changed, 2367 insertions(+), 2385 deletions(-) create mode 100644 src/actions/entrypoints/bump.ts create mode 100644 src/actions/entrypoints/validate.ts diff --git a/dist/bump/index.js b/dist/bump/index.js index 1597051b..e719ace6 100644 --- a/dist/bump/index.js +++ b/dist/bump/index.js @@ -33641,17 +33641,8 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.exportedForTesting = void 0; +exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); const github_1 = __nccwpck_require__(5438); const bump_1 = __nccwpck_require__(1692); @@ -33666,99 +33657,96 @@ const github_2 = __nccwpck_require__(978); * This action: * - takes inputs `config`, `version-prefix`, `create-release` and `create-tag` * - sets outputs `current-version` and `next-version` - */ -function run() { - return __awaiter(this, void 0, void 0, function* () { - // Try to download and load configuration - yield (0, github_2.getConfig)(core.getInput("config")); - const config = new config_1.Configuration(".commisery.yml"); - let isBranchAllowedToPublish = false; - const branchName = github_1.context.ref.replace("refs/heads/", ""); - if (github_1.context.ref.startsWith("refs/heads/")) { - try { - isBranchAllowedToPublish = new RegExp(config.allowedBranches).test(branchName); - } - catch (e) { - core.startGroup("❌ Configuration error - invalid 'allowed-branches' RegEx"); - core.setFailed(e.message); - core.endGroup(); - } - if (!isBranchAllowedToPublish) { - core.startGroup(`ℹ️ Branch ${branchName} is not allowed to publish`); - core.info(`Only branches that match the following ECMA-262 regular expression` + - `may publish:\n${config.allowedBranches}`); - } - } + * + * @internal + */ +async function run() { + // Try to download and load configuration + await (0, github_2.getConfig)(core.getInput("config")); + const config = new config_1.Configuration(".commisery.yml"); + let isBranchAllowedToPublish = false; + const branchName = github_1.context.ref.replace("refs/heads/", ""); + if (github_1.context.ref.startsWith("refs/heads/")) { try { - const prefix = core.getInput("version-prefix"); - if (prefix !== "") { - config.versionPrefix = prefix; - } - const release = core.getBooleanInput("create-release"); - const tag = core.getBooleanInput("create-tag"); - const releaseMode = release ? "release" : tag ? "tag" : "none"; - if (release && tag) { - core.warning('Defining both inputs "create-release" and "create-tag" as "true" is not needed; ' + - 'a Git tag is implicitly created when using "create-release".'); - } - core.startGroup("🔍 Finding latest topological tag.."); - const bumpInfo = yield (0, bump_1.getVersionBumpTypeAndMessages)(github_1.context.sha, config); - if (!bumpInfo.foundVersion) { - // We haven't found a (matching) SemVer tag in the commit and tag list - core.setOutput("current-version", ""); - core.setOutput("next-version", ""); - core.warning(`⚠️ No matching SemVer tags found.`); - core.endGroup(); - return; - } - else { - const currentVersion = bumpInfo.foundVersion.toString(); - core.info(`ℹ️ Found ${config.versionScheme === "semver" ? "SemVer" : "SdkVer"} tag: ${currentVersion}`); - core.setOutput("current-version", currentVersion); - } + isBranchAllowedToPublish = new RegExp(config.allowedBranches).test(branchName); + } + catch (e) { + core.startGroup("❌ Configuration error - invalid 'allowed-branches' RegEx"); + core.setFailed(e.message); core.endGroup(); - if (bumpInfo.foundVersion.major <= 0) { - core.info(""); - core.warning(config.initialDevelopment - ? "This repository is under 'initial development'; breaking changes will bump the `MINOR` version." - : "Enforcing version `1.0.0` as we are no longer in `initial development`."); - } - (0, bump_1.printNonCompliance)(bumpInfo.processedCommits); - const createChangelog = core.getBooleanInput("create-changelog"); + } + if (!isBranchAllowedToPublish) { + core.startGroup(`ℹ️ Branch ${branchName} is not allowed to publish`); + core.info(`Only branches that match the following ECMA-262 regular expression` + + `may publish:\n${config.allowedBranches}`); + } + } + try { + const prefix = core.getInput("version-prefix"); + if (prefix !== "") { + config.versionPrefix = prefix; + } + const release = core.getBooleanInput("create-release"); + const tag = core.getBooleanInput("create-tag"); + const releaseMode = release ? "release" : tag ? "tag" : "none"; + if (release && tag) { + core.warning('Defining both inputs "create-release" and "create-tag" as "true" is not needed; ' + + 'a Git tag is implicitly created when using "create-release".'); + } + core.startGroup("🔍 Finding latest topological tag.."); + const bumpInfo = await (0, bump_1.getVersionBumpTypeAndMessages)(github_1.context.sha, config); + if (!bumpInfo.foundVersion) { + // We haven't found a (matching) SemVer tag in the commit and tag list + core.setOutput("current-version", ""); + core.setOutput("next-version", ""); + core.warning(`⚠️ No matching SemVer tags found.`); + core.endGroup(); + return; + } + else { + const currentVersion = bumpInfo.foundVersion.toString(); + core.info(`ℹ️ Found ${config.versionScheme === "semver" ? "SemVer" : "SdkVer"} tag: ${currentVersion}`); + core.setOutput("current-version", currentVersion); + } + core.endGroup(); + if (bumpInfo.foundVersion.major <= 0) { core.info(""); - const releaseTypeInput = core.getInput("release-type"); - if (config.versionScheme === "semver") { - if (releaseTypeInput !== "") { - core.warning("The input value 'release-type' has no effect when using SemVer as the version scheme."); - } - core.startGroup("🔍 Determining SemVer bump"); - yield (0, bump_1.bumpSemVer)(config, bumpInfo, releaseMode, branchName, github_1.context.sha, isBranchAllowedToPublish, createChangelog); + core.warning(config.initialDevelopment + ? "This repository is under 'initial development'; breaking changes will bump the `MINOR` version." + : "Enforcing version `1.0.0` as we are no longer in `initial development`."); + } + (0, bump_1.printNonCompliance)(bumpInfo.processedCommits); + const createChangelog = core.getBooleanInput("create-changelog"); + core.info(""); + const releaseTypeInput = core.getInput("release-type"); + if (config.versionScheme === "semver") { + if (releaseTypeInput !== "") { + core.warning("The input value 'release-type' has no effect when using SemVer as the version scheme."); } - else if (config.versionScheme === "sdkver") { - if (!["rel", "rc", "dev", ""].includes(releaseTypeInput)) { - throw new Error("The input value 'release-type' must be one of: [rel, rc, dev]"); - } - const releaseType = (releaseTypeInput !== "" ? releaseTypeInput : "dev"); - core.startGroup("🔍 Determining SdkVer bump"); - // For non-release branches, a flow similar to SemVer can be followed, - // but release branches get linear increments. - yield (0, bump_1.bumpSdkVer)(config, bumpInfo, releaseMode, releaseType, github_1.context.sha, branchName, isBranchAllowedToPublish, createChangelog); - } - else { - throw new Error(`Unimplemented 'version-scheme': ${config.versionScheme}`); + core.startGroup("🔍 Determining SemVer bump"); + await (0, bump_1.bumpSemVer)(config, bumpInfo, releaseMode, branchName, github_1.context.sha, isBranchAllowedToPublish, createChangelog); + } + else if (config.versionScheme === "sdkver") { + if (!["rel", "rc", "dev", ""].includes(releaseTypeInput)) { + throw new Error("The input value 'release-type' must be one of: [rel, rc, dev]"); } + const releaseType = (releaseTypeInput !== "" ? releaseTypeInput : "dev"); + core.startGroup("🔍 Determining SdkVer bump"); + // For non-release branches, a flow similar to SemVer can be followed, + // but release branches get linear increments. + await (0, bump_1.bumpSdkVer)(config, bumpInfo, releaseMode, releaseType, github_1.context.sha, branchName, isBranchAllowedToPublish, createChangelog); } - catch (ex) { - core.startGroup("❌ Exception"); - core.setFailed(ex.message); - core.endGroup(); + else { + throw new Error(`Unimplemented 'version-scheme': ${config.versionScheme}`); } - }); + } + catch (ex) { + core.startGroup("❌ Exception"); + core.setFailed(ex.message); + core.endGroup(); + } } -run(); -exports.exportedForTesting = { - run, -}; +exports.run = run; /***/ }), @@ -33806,15 +33794,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.bumpSdkVer = exports.bumpSemVer = exports.publishBump = exports.printNonCompliance = exports.bumpDraftRelease = exports.getVersionBumpTypeAndMessages = exports.getVersionBumpType = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -33879,9 +33858,9 @@ function processCommitsForBump(commits, config) { // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = JSON.parse(JSON.stringify(config)); - configCopy.rules["C014"].enabled = false; // SubjectExceedsLineLengthLimit - configCopy.rules["C019"].enabled = false; // SubjectContainsIssueReference + const configCopy = Object.create(config); + configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference return (0, validate_1.processCommits)(commits, configCopy); } /** @@ -33923,57 +33902,55 @@ exports.getVersionBumpType = getVersionBumpType; - state of "initial development"; if no version is found, err on the safe side and declare "initial development" (if configured as such) */ -function getVersionBumpTypeAndMessages(targetSha, config) { - return __awaiter(this, void 0, void 0, function* () { - core.debug(`Fetching last ${PAGE_SIZE} tags from ${targetSha}..`); - const tags = yield (0, github_1.getLatestTags)(PAGE_SIZE); - core.debug("Fetch complete"); - const tagMatcher = (commitMessage, commitSha) => { - // Try and match this commit's hash to one of the tags in `tags` - for (const tag of tags) { - let semVer = null; - core.debug(`Considering tag ${tag.name} (${tag.commitSha}) on ${commitSha}`); - semVer = getSemVerIfMatches(config.versionPrefix, tag.name, tag.commitSha, commitSha); - if (semVer) { - // We've found a tag that matches to this commit. Now, we need to - // make sure that we return the _highest_ version tag_ associated with - // this commit - core.debug(`Matching tag found (${tag.name}), checking other tags for commit ${commitSha}..`); - const matchTags = tags.filter(t => t.commitSha === commitSha); - if (matchTags.length > 1) { - core.debug(`${matchTags.length} other tags found`); - matchTags.sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); - semVer = null; - while (semVer === null && matchTags.length !== 0) { - const t = matchTags.pop(); - if (!t) - break; - semVer = getSemVerIfMatches(config.versionPrefix, t.name, t.commitSha, commitSha); - } - } - else { - core.debug(`No other tags found`); - // Just the one tag; carry on. +async function getVersionBumpTypeAndMessages(targetSha, config) { + core.debug(`Fetching last ${PAGE_SIZE} tags from ${targetSha}..`); + const tags = await (0, github_1.getLatestTags)(PAGE_SIZE); + core.debug("Fetch complete"); + const tagMatcher = (commitSha) => { + // Try and match this commit's hash to one of the tags in `tags` + for (const tag of tags) { + let semVer = null; + core.debug(`Considering tag ${tag.name} (${tag.commitSha}) on ${commitSha}`); + semVer = getSemVerIfMatches(config.versionPrefix, tag.name, tag.commitSha, commitSha); + if (semVer) { + // We've found a tag that matches to this commit. Now, we need to + // make sure that we return the _highest_ version tag_ associated with + // this commit + core.debug(`Matching tag found (${tag.name}), checking other tags for commit ${commitSha}..`); + const matchTags = tags.filter(t => t.commitSha === commitSha); + if (matchTags.length > 1) { + core.debug(`${matchTags.length} other tags found`); + matchTags.sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); + semVer = null; + while (semVer === null && matchTags.length !== 0) { + const t = matchTags.pop(); + if (!t) + break; + semVer = getSemVerIfMatches(config.versionPrefix, t.name, t.commitSha, commitSha); } - return semVer; } + else { + core.debug(`No other tags found`); + // Just the one tag; carry on. + } + return semVer; } - core.debug(`Commit ${commitSha.slice(0, 6)} is not associated with a tag`); - return null; - }; - const [version, commitList] = yield (0, github_1.matchTagsToCommits)(targetSha, tagMatcher); - const results = processCommitsForBump(commitList, config); - const convCommits = results - .map(r => r.message) - .filter((r) => r !== undefined); - return { - foundVersion: version, - requiredBump: getVersionBumpType(convCommits), - processedCommits: results, - initialDevelopment: config.initialDevelopment && - (!version || (version && version.major === 0)), - }; - }); + } + core.debug(`Commit ${commitSha.slice(0, 6)} is not associated with a tag`); + return null; + }; + const [version, commitList] = await (0, github_1.matchTagsToCommits)(targetSha, tagMatcher); + const results = processCommitsForBump(commitList, config); + const convCommits = results + .map(r => r.message) + .filter((r) => r !== undefined); + return { + foundVersion: version, + requiredBump: getVersionBumpType(convCommits), + processedCommits: results, + initialDevelopment: config.initialDevelopment && + (!version || (version && version.major === 0)), + }; } exports.getVersionBumpTypeAndMessages = getVersionBumpTypeAndMessages; /** @@ -33988,57 +33965,51 @@ exports.getVersionBumpTypeAndMessages = getVersionBumpTypeAndMessages; * Returns the new prerelease version name if update was successful, * `undefined` otherwise. */ -function tryUpdateDraftRelease(cv, changelog, sha) { - return __awaiter(this, void 0, void 0, function* () { - const latestDraftRelease = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, - draftOnly: true, - fullReleasesOnly: false, - }); - if (!latestDraftRelease) - return; - const currentDraftVersion = semver_1.SemVer.fromString(latestDraftRelease.name); - if (!currentDraftVersion) { - core.info(`Couldn't parse ${latestDraftRelease.name} as SemVer`); - return; - } - const npv = currentDraftVersion.nextPrerelease(); - if (!npv) - return; - npv.build = shortSha(sha); - const updateSuccess = yield (0, github_1.updateDraftRelease)(latestDraftRelease.id, npv.toString(), npv.toString(), sha, changelog); - if (!updateSuccess) { - core.info(`Error renaming existing draft release.`); - return; - } - return npv.toString(); +async function tryUpdateDraftRelease(cv, changelog, sha) { + const latestDraftRelease = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: true, + fullReleasesOnly: false, }); + if (!latestDraftRelease) + return; + const currentDraftVersion = semver_1.SemVer.fromString(latestDraftRelease.name); + if (!currentDraftVersion) { + core.info(`Couldn't parse ${latestDraftRelease.name} as SemVer`); + return; + } + const npv = currentDraftVersion.nextPrerelease(); + if (!npv) + return; + npv.build = shortSha(sha); + const updateSuccess = await (0, github_1.updateDraftRelease)(latestDraftRelease.id, npv.toString(), npv.toString(), sha, changelog); + if (!updateSuccess) { + core.info(`Error renaming existing draft release.`); + return; + } + return npv.toString(); } -function newDraftRelease(currentVersion, changelog, sha, prefix) { - return __awaiter(this, void 0, void 0, function* () { - // Either update went wrong or there was nothing to update - const nextPrereleaseVersion = currentVersion.nextPatch(); - nextPrereleaseVersion.build = currentVersion.build; - if (prefix === "dev") { - nextPrereleaseVersion.prerelease = `${prefix}001.${shortSha(sha)}`; - } - else { - nextPrereleaseVersion.prerelease = `${prefix}001`; - } - yield (0, github_1.createRelease)(nextPrereleaseVersion.toString(), sha, changelog, true, false); - return nextPrereleaseVersion.toString(); - }); +async function newDraftRelease(currentVersion, changelog, sha, prefix) { + // Either update went wrong or there was nothing to update + const nextPrereleaseVersion = currentVersion.nextPatch(); + nextPrereleaseVersion.build = currentVersion.build; + if (prefix === "dev") { + nextPrereleaseVersion.prerelease = `${prefix}001.${shortSha(sha)}`; + } + else { + nextPrereleaseVersion.prerelease = `${prefix}001`; + } + await (0, github_1.createRelease)(nextPrereleaseVersion.toString(), sha, changelog, true, false); + return nextPrereleaseVersion.toString(); } -function bumpDraftRelease(bumpInfo, changelog, sha, preRelPrefix) { +async function bumpDraftRelease(bumpInfo, changelog, sha, preRelPrefix) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const cv = bumpInfo.foundVersion; - if (!cv) - throw Error("Found version is falsy"); // should never happen - const result = (_a = (yield tryUpdateDraftRelease(cv, changelog, sha))) !== null && _a !== void 0 ? _a : (yield newDraftRelease(cv, changelog, sha, preRelPrefix)); - core.info(`ℹ️ Next prerelease: ${result}`); - return result; - }); + const cv = bumpInfo.foundVersion; + if (!cv) + throw Error("Found version is falsy"); // should never happen + const result = (_a = (await tryUpdateDraftRelease(cv, changelog, sha))) !== null && _a !== void 0 ? _a : (await newDraftRelease(cv, changelog, sha, preRelPrefix)); + core.info(`ℹ️ Next prerelease: ${result}`); + return result; } exports.bumpDraftRelease = bumpDraftRelease; /** @@ -34071,146 +34042,142 @@ function printNonCompliance(commits) { } } exports.printNonCompliance = printNonCompliance; -function publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, updateDraftId) { - return __awaiter(this, void 0, void 0, function* () { - const nv = nextVersion.toString(); - core.info(`ℹ️ Next version: ${nv}`); - core.setOutput("next-version", nv); - core.endGroup(); - if (releaseMode !== "none") { - if (!isBranchAllowedToPublish) { - return false; - } - if ((0, github_1.isPullRequestEvent)()) { - core.startGroup(`ℹ️ Not creating ${releaseMode} on a pull request event.`); - core.info("We cannot create a release or tag in a pull request context, due to " + - "potential parallelism (i.e. races) in pull request builds."); - return false; +async function publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, updateDraftId) { + const nv = nextVersion.toString(); + core.info(`ℹ️ Next version: ${nv}`); + core.setOutput("next-version", nv); + core.endGroup(); + if (releaseMode !== "none") { + if (!isBranchAllowedToPublish) { + return false; + } + if ((0, github_1.isPullRequestEvent)()) { + core.startGroup(`ℹ️ Not creating ${releaseMode} on a pull request event.`); + core.info("We cannot create a release or tag in a pull request context, due to " + + "potential parallelism (i.e. races) in pull request builds."); + return false; + } + core.startGroup(`ℹ️ Creating ${releaseMode} ${nv}..`); + try { + if (releaseMode === "tag") { + await (0, github_1.createTag)(nv, headSha); } - core.startGroup(`ℹ️ Creating ${releaseMode} ${nv}..`); - try { - if (releaseMode === "tag") { - yield (0, github_1.createTag)(nv, headSha); - } - else { - // If version is a prerelease, but not an RC, create a draft release - // If version is an RC, create a GitHub "pre-release" - const isRc = nextVersion.prerelease.startsWith(RC_PREFIX); - const isDev = nextVersion.prerelease !== "" && !isRc; - let updated = false; - if (updateDraftId) { - updated = yield (0, github_1.updateDraftRelease)(updateDraftId, nv, nv, headSha, changelog, isDev, // draft - isRc // prerelease - ); - if (!updated) { - core.info(`Error renaming existing draft release, ` + - `creating new draft release.`); - } - } + else { + // If version is a prerelease, but not an RC, create a draft release + // If version is an RC, create a GitHub "pre-release" + const isRc = nextVersion.prerelease.startsWith(RC_PREFIX); + const isDev = nextVersion.prerelease !== "" && !isRc; + let updated = false; + if (updateDraftId) { + updated = await (0, github_1.updateDraftRelease)(updateDraftId, nv, nv, headSha, changelog, isDev, // draft + isRc // prerelease + ); if (!updated) { - yield (0, github_1.createRelease)(nv, headSha, changelog, isDev, isRc); + core.info(`Error renaming existing draft release, ` + + `creating new draft release.`); } } - } - catch (ex) { - // The most likely failure is a preexisting tag, in which case - // a RequestError with statuscode 422 will be thrown - const commit = yield (0, github_1.getShaForTag)(`refs/tags/${nv}`); - if (ex instanceof request_error_1.RequestError && ex.status === 422 && commit) { - core.setFailed(`Unable to create ${releaseMode}; the tag "${nv}" already exists in the repository, ` + - `it currently points to ${commit}.\n` + - "You can find the branch(es) associated with the tag with:\n" + - ` git fetch -t; git branch --contains ${nv}`); - } - else if (ex instanceof request_error_1.RequestError) { - core.setFailed(`Unable to create ${releaseMode} with the name "${nv}" due to ` + - `HTTP request error (status ${ex.status}):\n${ex.message}`); - } - else if (ex instanceof Error) { - core.setFailed(`Unable to create ${releaseMode} with the name "${nv}":\n${ex.message}`); + if (!updated) { + await (0, github_1.createRelease)(nv, headSha, changelog, isDev, isRc); } - else { - core.setFailed(`Unknown error during ${releaseMode} creation`); - throw ex; - } - core.endGroup(); - return false; } - core.info("Succeeded"); } - else { - core.startGroup(`ℹ️ Not creating tag or release for ${nv}..`); - core.info("To create a lightweight Git tag or GitHub release when the version is bumped, run this action with:\n" + - ' - "create-release" set to "true" to create a GitHub release, or\n' + - ' - "create-tag" set to "true" for a lightweight Git tag.\n' + - "Note that setting both options is not needed, since a GitHub release implicitly creates a Git tag."); + catch (ex) { + // The most likely failure is a preexisting tag, in which case + // a RequestError with statuscode 422 will be thrown + const commit = await (0, github_1.getShaForTag)(`refs/tags/${nv}`); + if (ex instanceof request_error_1.RequestError && ex.status === 422 && commit) { + core.setFailed(`Unable to create ${releaseMode}; the tag "${nv}" already exists in the repository, ` + + `it currently points to ${commit}.\n` + + "You can find the branch(es) associated with the tag with:\n" + + ` git fetch -t; git branch --contains ${nv}`); + } + else if (ex instanceof request_error_1.RequestError) { + core.setFailed(`Unable to create ${releaseMode} with the name "${nv}" due to ` + + `HTTP request error (status ${ex.status}):\n${ex.message}`); + } + else if (ex instanceof Error) { + core.setFailed(`Unable to create ${releaseMode} with the name "${nv}":\n${ex.message}`); + } + else { + core.setFailed(`Unknown error during ${releaseMode} creation`); + throw ex; + } + core.endGroup(); return false; } - return true; - }); + core.info("Succeeded"); + } + else { + core.startGroup(`ℹ️ Not creating tag or release for ${nv}..`); + core.info("To create a lightweight Git tag or GitHub release when the version is bumped, run this action with:\n" + + ' - "create-release" set to "true" to create a GitHub release, or\n' + + ' - "create-tag" set to "true" for a lightweight Git tag.\n' + + "Note that setting both options is not needed, since a GitHub release implicitly creates a Git tag."); + return false; + } + return true; } exports.publishBump = publishBump; -function bumpSemVer(config, bumpInfo, releaseMode, branchName, headSha, isBranchAllowedToPublish, createChangelog) { +async function bumpSemVer(config, bumpInfo, releaseMode, branchName, headSha, isBranchAllowedToPublish, createChangelog) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const compliantCommits = bumpInfo.processedCommits - .filter(c => c.message !== undefined) - .map(c => ({ - msg: c.message, - sha: c.input.sha.slice(0, 8), - })); - for (const { msg, sha } of compliantCommits) { - const bumpString = msg.bump === 0 ? "No" : semver_1.SemVerType[msg.bump]; - core.info(`- ${bumpString} bump for commit (${sha}): ${msg.subject}`); - } - // Reject MAJOR and MINOR version bumps if we're on a release branch - // (Purposefully do this check _after_ listing the processed commits.) - if (branchName.match(config.releaseBranches) && - [semver_1.SemVerType.MAJOR, semver_1.SemVerType.MINOR].includes(bumpInfo.requiredBump)) { - core.setFailed(`A ${semver_1.SemVerType[bumpInfo.requiredBump]} bump is requested, but ` + - `we can only create PATCH bumps on a release branch.`); - return false; + const compliantCommits = bumpInfo.processedCommits + .filter(c => c.message !== undefined) + .map(c => ({ + msg: c.message, + sha: c.input.sha.slice(0, 8), + })); + for (const { msg, sha } of compliantCommits) { + const bumpString = msg.bump === 0 ? "No" : semver_1.SemVerType[msg.bump]; + core.info(`- ${bumpString} bump for commit (${sha}): ${msg.subject}`); + } + // Reject MAJOR and MINOR version bumps if we're on a release branch + // (Purposefully do this check _after_ listing the processed commits.) + if (branchName.match(config.releaseBranches) && + [semver_1.SemVerType.MAJOR, semver_1.SemVerType.MINOR].includes(bumpInfo.requiredBump)) { + core.setFailed(`A ${semver_1.SemVerType[bumpInfo.requiredBump]} bump is requested, but ` + + `we can only create PATCH bumps on a release branch.`); + return false; + } + const nextVersion = (_a = bumpInfo.foundVersion) === null || _a === void 0 ? void 0 : _a.bump(bumpInfo.requiredBump, config.initialDevelopment); + let changelog = ""; + if (createChangelog) + changelog = await (0, changelog_1.generateChangelog)(bumpInfo); + let bumped = false; + if (nextVersion) { + const buildMetadata = core.getInput("build-metadata"); + if (buildMetadata) { + nextVersion.build = buildMetadata; } - const nextVersion = (_a = bumpInfo.foundVersion) === null || _a === void 0 ? void 0 : _a.bump(bumpInfo.requiredBump, config.initialDevelopment); - let changelog = ""; - if (createChangelog) - changelog = yield (0, changelog_1.generateChangelog)(bumpInfo); - let bumped = false; - if (nextVersion) { - const buildMetadata = core.getInput("build-metadata"); - if (buildMetadata) { - nextVersion.build = buildMetadata; - } - bumped = yield publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish); + bumped = await publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish); + } + else { + core.info("ℹ️ No bump necessary"); + core.setOutput("next-version", ""); + } + core.endGroup(); + if (!bumped && config.prereleasePrefix !== undefined) { + // When configured to create GitHub releases, and the `bump-prereleases` config item + // evaluates to `true`. + if (isBranchAllowedToPublish && + !(0, github_1.isPullRequestEvent)() && + releaseMode === "release") { + // Create/rename draft release + const ver = await bumpDraftRelease(bumpInfo, changelog, headSha, config.prereleasePrefix); + core.info(`ℹ️ Created draft prerelease version ${ver}`); } else { - core.info("ℹ️ No bump necessary"); - core.setOutput("next-version", ""); + const reason = isBranchAllowedToPublish !== true + ? `the current branch is not allowed to publish` + : (0, github_1.isPullRequestEvent)() + ? "we cannot publish from a pull request event" + : releaseMode !== "release" + ? `we can only do so when the 'create-release' input is provided to be 'true'` + : "we didn't think of writing an error message here"; + core.info(`ℹ️ While configured to bump prereleases, ${reason}.`); } - core.endGroup(); - if (!bumped && config.prereleasePrefix !== undefined) { - // When configured to create GitHub releases, and the `bump-prereleases` config item - // evaluates to `true`. - if (isBranchAllowedToPublish && - !(0, github_1.isPullRequestEvent)() && - releaseMode === "release") { - // Create/rename draft release - const ver = yield bumpDraftRelease(bumpInfo, changelog, headSha, config.prereleasePrefix); - core.info(`ℹ️ Created draft prerelease version ${ver}`); - } - else { - const reason = isBranchAllowedToPublish !== true - ? `the current branch is not allowed to publish` - : (0, github_1.isPullRequestEvent)() - ? "we cannot publish from a pull request event" - : releaseMode !== "release" - ? `we can only do so when the 'create-release' input is provided to be 'true'` - : "we didn't think of writing an error message here"; - core.info(`ℹ️ While configured to bump prereleases, ${reason}.`); - } - } - return bumped; - }); + } + return bumped; } exports.bumpSemVer = bumpSemVer; function getNextSdkVer(currentVersion, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, devPrereleaseText, headSha, isInitialDevelopment) { @@ -34382,115 +34349,113 @@ function getNextSdkVer(currentVersion, sdkVerBumpType, isReleaseBranch, headMatc /** * Bump and release/tag SDK versions */ -function bumpSdkVer(config, bumpInfo, releaseMode, sdkVerBumpType, headSha, branchName, isBranchAllowedToPublish, createChangelog) { +async function bumpSdkVer(config, bumpInfo, releaseMode, sdkVerBumpType, headSha, branchName, isBranchAllowedToPublish, createChangelog) { var _a, _b, _c, _d, _e, _f; - return __awaiter(this, void 0, void 0, function* () { - const isReleaseBranch = branchName.match(config.releaseBranches); - const hasBreakingChange = bumpInfo.processedCommits.some(c => { var _a; return (_a = c.message) === null || _a === void 0 ? void 0 : _a.breakingChange; }); - if (!bumpInfo.foundVersion) - return false; // should never happen - // SdkVer requires a prerelease, so apply the default if not set - config.prereleasePrefix = (_a = config.prereleasePrefix) !== null && _a !== void 0 ? _a : "dev"; - let cv = semver_1.SemVer.copy(bumpInfo.foundVersion); - // Get the latest draft release matching our current version's prefix. - // Don't look at the draft version on a release branch; the current version - // should always reflect the version to be bumped (as no dev releases are - // allowed on a release branch) - const latestDraft = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, - draftOnly: true, - fullReleasesOnly: false, - }); - const latestRelease = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, + const isReleaseBranch = branchName.match(config.releaseBranches) !== null; + const hasBreakingChange = bumpInfo.processedCommits.some(c => { var _a; return (_a = c.message) === null || _a === void 0 ? void 0 : _a.breakingChange; }); + if (!bumpInfo.foundVersion) + return false; // should never happen + // SdkVer requires a prerelease, so apply the default if not set + config.prereleasePrefix = (_a = config.prereleasePrefix) !== null && _a !== void 0 ? _a : "dev"; + let cv = semver_1.SemVer.copy(bumpInfo.foundVersion); + // Get the latest draft release matching our current version's prefix. + // Don't look at the draft version on a release branch; the current version + // should always reflect the version to be bumped (as no dev releases are + // allowed on a release branch) + const latestDraft = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: true, + fullReleasesOnly: false, + }); + const latestRelease = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: false, + fullReleasesOnly: true, + }); + core.info(`Current version: ${cv.toString()}, latest GitHub release draft: ${(_b = latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.name) !== null && _b !== void 0 ? _b : "NONE"}, latest GitHub release: ${(_c = latestRelease === null || latestRelease === void 0 ? void 0 : latestRelease.name) !== null && _c !== void 0 ? _c : "NONE"}`); + if (!isReleaseBranch && latestDraft) { + // If we're not on a release branch and a draft version exists that is + // newer than the latest tag, we continue with that + const draftVersion = semver_1.SemVer.fromString(latestDraft.name); + if (draftVersion && cv.lessThan(draftVersion)) { + cv = draftVersion; + } + } + // TODO: This is wasteful, as this info has already been available before + const headMatchesTag = await (0, github_1.currentHeadMatchesTag)(cv.toString()); + const nextVersion = getNextSdkVer(cv, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, (_d = config.prereleasePrefix) !== null && _d !== void 0 ? _d : "dev", headSha, config.initialDevelopment); + let bumped = false; + if (nextVersion) { + // Since we want the changelog since the last _full_ release, we + // can only rely on the `bumpInfo` if the "current version" is a + // full release. In other cases, we need to gather some information + // to generate the proper changelog. + const previousRelease = await (0, github_1.getRelease)({ + prefixToMatch: nextVersion.prefix, draftOnly: false, fullReleasesOnly: true, + constraint: { + major: nextVersion.major, + minor: nextVersion.minor, + }, }); - core.info(`Current version: ${cv.toString()}, latest GitHub release draft: ${(_b = latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.name) !== null && _b !== void 0 ? _b : "NONE"}, latest GitHub release: ${(_c = latestRelease === null || latestRelease === void 0 ? void 0 : latestRelease.name) !== null && _c !== void 0 ? _c : "NONE"}`); - if (!isReleaseBranch && latestDraft) { - // If we're not on a release branch and a draft version exists that is - // newer than the latest tag, we continue with that - const draftVersion = semver_1.SemVer.fromString(latestDraft.name); - if (draftVersion && cv.lessThan(draftVersion)) { - cv = draftVersion; + core.info(`The full release preceding the current one is ${(_e = previousRelease === null || previousRelease === void 0 ? void 0 : previousRelease.name) !== null && _e !== void 0 ? _e : "undefined"}`); + let changelog = ""; + if (createChangelog) { + if (previousRelease && cv.prerelease) { + const toVersion = + // Since "dev" releases on non-release-branches result in a draft + // release, we'll need to use the commit sha. + sdkVerBumpType === "dev" && !isReleaseBranch + ? shortSha(headSha) + : nextVersion.toString(); + changelog = await (0, changelog_1.generateChangelogForCommits)(previousRelease.name, toVersion, await collectChangelogCommits(previousRelease.name, config)); + } + else { + changelog = await (0, changelog_1.generateChangelog)(bumpInfo); } } - // TODO: This is wasteful, as this info has already been available before - const headMatchesTag = yield (0, github_1.currentHeadMatchesTag)(cv.toString()); - const nextVersion = getNextSdkVer(cv, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, (_d = config.prereleasePrefix) !== null && _d !== void 0 ? _d : "dev", headSha, config.initialDevelopment); - let bumped = false; - if (nextVersion) { - // Since we want the changelog since the last _full_ release, we - // can only rely on the `bumpInfo` if the "current version" is a - // full release. In other cases, we need to gather some information - // to generate the proper changelog. - const previousRelease = yield (0, github_1.getRelease)({ - prefixToMatch: nextVersion.prefix, - draftOnly: false, - fullReleasesOnly: true, - constraint: { - major: nextVersion.major, - minor: nextVersion.minor, - }, - }); - core.info(`The full release preceding the current one is ${(_e = previousRelease === null || previousRelease === void 0 ? void 0 : previousRelease.name) !== null && _e !== void 0 ? _e : "undefined"}`); - let changelog = ""; - if (createChangelog) { - if (previousRelease && cv.prerelease) { - const toVersion = - // Since "dev" releases on non-release-branches result in a draft - // release, we'll need to use the commit sha. - sdkVerBumpType === "dev" && !isReleaseBranch - ? shortSha(headSha) - : nextVersion.toString(); - changelog = yield (0, changelog_1.generateChangelogForCommits)(previousRelease.name, toVersion, yield collectChangelogCommits(previousRelease.name, config)); + bumped = await publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, + // Re-use the latest draft release only when not running on a release branch, + // otherwise we might randomly reset a `dev-N` number chain. + !isReleaseBranch ? latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.id : undefined); + } + if (!bumped) { + core.info("ℹ️ No bump was performed"); + } + else { + // Create a release branch for releases and RC's if we're configured to do so + // and are currently not running on a release branch. + if (config.sdkverCreateReleaseBranches !== undefined && + !isReleaseBranch && + sdkVerBumpType !== "dev") { + const releaseBranchName = `${config.sdkverCreateReleaseBranches}${nextVersion.major}.${nextVersion.minor}`; + core.info(`Creating release branch ${releaseBranchName}..`); + try { + await (0, github_1.createBranch)(`refs/heads/${releaseBranchName}`, headSha); + } + catch (ex) { + if (ex instanceof request_error_1.RequestError && ex.status === 422) { + core.warning(`The branch '${releaseBranchName}' already exists` + + `${(0, github_1.getRunNumber)() !== 1 ? " (NOTE: this is a re-run)." : "."}`); } - else { - changelog = yield (0, changelog_1.generateChangelog)(bumpInfo); + else if (ex instanceof request_error_1.RequestError) { + core.warning(`Unable to create release branch '${releaseBranchName}' due to ` + + `HTTP request error (status ${ex.status}):\n${ex.message}`); } - } - bumped = yield publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, - // Re-use the latest draft release only when not running on a release branch, - // otherwise we might randomly reset a `dev-N` number chain. - !isReleaseBranch ? latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.id : undefined); - } - if (!bumped) { - core.info("ℹ️ No bump was performed"); - } - else { - // Create a release branch for releases and RC's if we're configured to do so - // and are currently not running on a release branch. - if (config.sdkverCreateReleaseBranches !== undefined && - !isReleaseBranch && - sdkVerBumpType !== "dev") { - const releaseBranchName = `${config.sdkverCreateReleaseBranches}${nextVersion.major}.${nextVersion.minor}`; - core.info(`Creating release branch ${releaseBranchName}..`); - try { - yield (0, github_1.createBranch)(`refs/heads/${releaseBranchName}`, headSha); + else if (ex instanceof Error) { + core.warning(`Unable to create release branch '${releaseBranchName}':\n${ex.message}`); } - catch (ex) { - if (ex instanceof request_error_1.RequestError && ex.status === 422) { - core.warning(`The branch '${releaseBranchName}' already exists` + - `${(0, github_1.getRunNumber)() !== 1 ? " (NOTE: this is a re-run)." : "."}`); - } - else if (ex instanceof request_error_1.RequestError) { - core.warning(`Unable to create release branch '${releaseBranchName}' due to ` + - `HTTP request error (status ${ex.status}):\n${ex.message}`); - } - else if (ex instanceof Error) { - core.warning(`Unable to create release branch '${releaseBranchName}':\n${ex.message}`); - } - else { - core.warning(`Unknown error during ${releaseMode} creation`); - throw ex; - } + else { + core.warning(`Unknown error during ${releaseMode} creation`); + throw ex; } } } - core.setOutput("next-version", (_f = nextVersion === null || nextVersion === void 0 ? void 0 : nextVersion.toString()) !== null && _f !== void 0 ? _f : ""); - core.endGroup(); - return bumped; - }); + } + core.setOutput("next-version", (_f = nextVersion === null || nextVersion === void 0 ? void 0 : nextVersion.toString()) !== null && _f !== void 0 ? _f : ""); + core.endGroup(); + return bumped; } exports.bumpSdkVer = bumpSdkVer; /** @@ -34502,19 +34467,17 @@ exports.bumpSdkVer = bumpSdkVer; * - the name of the last full release reachable from our current version * - the list of valid Conventional Commit objects since that release */ -function collectChangelogCommits(previousRelease, config) { - return __awaiter(this, void 0, void 0, function* () { - core.startGroup(`📜 Gathering changelog information`); - const commits = yield (0, github_1.getCommitsBetweenRefs)(previousRelease); - core.info(`Processing commit list (since ${previousRelease}) ` + - `for changelog generation:\n-> ` + - `${commits.map(c => c.message.split("\n")[0]).join("\n-> ")}`); - const processedCommits = processCommitsForBump(commits, config); - core.endGroup(); - return processedCommits - .map(c => c.message) - .filter(c => c); - }); +async function collectChangelogCommits(previousRelease, config) { + core.startGroup(`📜 Gathering changelog information`); + const commits = await (0, github_1.getCommitsBetweenRefs)(previousRelease); + core.info(`Processing commit list (since ${previousRelease}) ` + + `for changelog generation:\n-> ` + + `${commits.map(c => c.message.split("\n")[0]).join("\n-> ")}`); + const processedCommits = processCommitsForBump(commits, config); + core.endGroup(); + return processedCommits + .map(c => c.message) + .filter(c => c); } @@ -34563,15 +34526,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateChangelog = exports.generateChangelogForCommits = exports.getChangelogConfiguration = void 0; const github_1 = __nccwpck_require__(5438); @@ -34614,20 +34568,18 @@ const DEFAULT_CONFIG = { * Generates a Pull Request suffix `(#123)` in case this is not yet present * in the commit description. */ -function getPullRequestSuffix(commit) { - return __awaiter(this, void 0, void 0, function* () { - if (commit.hexsha && !commit.description.match(/\s\(#[0-9]+\)$/)) { - const pull_requests = yield (0, github_2.getAssociatedPullRequests)(commit.hexsha); - const pr_references = []; - for (const pull_request of pull_requests) { - pr_references.push(`#${pull_request.number}`); - } - if (pr_references.length > 0) { - return ` (${pr_references.join(", ")})`; - } +async function getPullRequestSuffix(commit) { + if (commit.hexsha && !commit.description.match(/\s\(#[0-9]+\)$/)) { + const pull_requests = await (0, github_2.getAssociatedPullRequests)(commit.hexsha); + const pr_references = []; + for (const pull_request of pull_requests) { + pr_references.push(`#${pull_request.number}`); } - return ""; - }); + if (pr_references.length > 0) { + return ` (${pr_references.join(", ")})`; + } + } + return ""; } /** * Generates an Issue suffix `(TEST-123, TEST-456)` based on the issue @@ -34651,37 +34603,33 @@ function getIssueReferenceSuffix(commit) { * Creates an entry in the Changelog based on the provided * Conventional Commit message. */ -function generateChangelogEntry(commit) { - return __awaiter(this, void 0, void 0, function* () { - const { owner, repo } = github_1.context.repo; - let changelogEntry = `${commit.description - .charAt(0) - .toUpperCase()}${commit.description.slice(1)}`; - changelogEntry += yield getPullRequestSuffix(commit); - changelogEntry += getIssueReferenceSuffix(commit); - if (commit.hexsha) { - const sha_link = `[${commit.hexsha.slice(0, 6)}](https://github.com/${owner}/${repo}/commit/${commit.hexsha})`; - changelogEntry += ` [${sha_link}]`; - } - return changelogEntry; - }); +async function generateChangelogEntry(commit) { + const { owner, repo } = github_1.context.repo; + let changelogEntry = `${commit.description + .charAt(0) + .toUpperCase()}${commit.description.slice(1)}`; + changelogEntry += await getPullRequestSuffix(commit); + changelogEntry += getIssueReferenceSuffix(commit); + if (commit.hexsha) { + const sha_link = `[${commit.hexsha.slice(0, 6)}](https://github.com/${owner}/${repo}/commit/${commit.hexsha})`; + changelogEntry += ` [${sha_link}]`; + } + return changelogEntry; } /** * Returns the Changelog configuration; * - The contents of the .github/release.y[a]ml file * - Otherwise, the internal default configuration */ -function getChangelogConfiguration() { - return __awaiter(this, void 0, void 0, function* () { - const githubReleaseConfig = yield (0, github_2.getReleaseConfiguration)(); - if (githubReleaseConfig.length > 0) { - const data = yaml.parse(githubReleaseConfig); - if (data["changelog"] !== undefined) { - return data; - } +async function getChangelogConfiguration() { + const githubReleaseConfig = await (0, github_2.getReleaseConfiguration)(); + if (githubReleaseConfig.length > 0) { + const data = yaml.parse(githubReleaseConfig); + if (data["changelog"] !== undefined) { + return data; } - return JSON.parse(JSON.stringify(DEFAULT_CONFIG)); - }); + } + return JSON.parse(JSON.stringify(DEFAULT_CONFIG)); } exports.getChangelogConfiguration = getChangelogConfiguration; /** @@ -34694,116 +34642,112 @@ exports.getChangelogConfiguration = getChangelogConfiguration; * `endVersion` can be an empty string, in which case the current HEAD sha * will be used. */ -function generateChangelogForCommits(startVersion, endVersion, commitList) { +async function generateChangelogForCommits(startVersion, endVersion, commitList) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; - return __awaiter(this, void 0, void 0, function* () { - if (startVersion === "") { - return ""; + if (startVersion === "") { + return ""; + } + const config = await getChangelogConfiguration(); + const changelog = new Map(); + for (const commit of commitList) { + if (!commit) + continue; + const bumpLabel = Label.create("bump", semver_1.SemVerType[commit.bump]); + const typeLabel = Label.create("type", commit.type); + const scopeLabel = Label.create("scope", ((_a = commit.scope) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "*"); + // Adds the following items as "virtual" labels for each commit: + // * The version bump (`bump:`) + // * The conventional commit type (`type:`) + // * The conventional commit scope (`scope:`) + let labels = [bumpLabel, typeLabel, scopeLabel]; + // We will reuse the labels and author associated with a Pull Request + // (with the exception of `bump:` and `scope:`) for all + // commits associated with the PR. + if (commit.hexsha) { + const pullRequests = await (0, github_2.getAssociatedPullRequests)(commit.hexsha); + if (pullRequests.length > 0) { + const pullRequest = pullRequests[0]; + // Append the labels of the associated Pull Request + // NOTE: we ignore the version bump and scope label on the PR as this is + // and instead rely on version bump label associated with this + // commit. + labels = labels.concat(pullRequest.labels + .filter(label => !Label.isCategory(label.name, "bump") && + !Label.isCategory(label.name, "scope")) + .map(label => label.name)); + // Check if the author of the Pull Request is part of the exclude list + if (pullRequest.user && + ((_c = (_b = config.changelog.exclude) === null || _b === void 0 ? void 0 : _b.authors) === null || _c === void 0 ? void 0 : _c.includes(pullRequest.user.login))) { + continue; + } + } + } + // Check if any of the labels is part of the global exclusion list + if (labels.some(label => { var _a, _b; return (_b = (_a = config.changelog.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { + continue; } - const config = yield getChangelogConfiguration(); - const changelog = new Map(); - for (const commit of commitList) { - if (!commit) + // Either group commits per Conventional Commit scope, or group them all + // together (*) + const scope = config.changelog.group === "scope" + ? ((_d = commit === null || commit === void 0 ? void 0 : commit.scope) === null || _d === void 0 ? void 0 : _d.toLowerCase()) || "*" + : "*"; + changelog.set(scope, (_e = changelog.get(scope)) !== null && _e !== void 0 ? _e : new Map()); + for (const category of config.changelog.categories) { + // Apply all exclusion patterns from Pull Request metadata on Category + if (labels.some(label => { var _a, _b; return (_b = (_a = category.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { continue; - const bumpLabel = Label.create("bump", semver_1.SemVerType[commit.bump]); - const typeLabel = Label.create("type", commit.type); - const scopeLabel = Label.create("scope", ((_a = commit.scope) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "*"); - // Adds the following items as "virtual" labels for each commit: - // * The version bump (`bump:`) - // * The conventional commit type (`type:`) - // * The conventional commit scope (`scope:`) - let labels = [bumpLabel, typeLabel, scopeLabel]; - // We will reuse the labels and author associated with a Pull Request - // (with the exception of `bump:` and `scope:`) for all - // commits associated with the PR. - if (commit.hexsha) { - const pullRequests = yield (0, github_2.getAssociatedPullRequests)(commit.hexsha); - if (pullRequests.length > 0) { - const pullRequest = pullRequests[0]; - // Append the labels of the associated Pull Request - // NOTE: we ignore the version bump and scope label on the PR as this is - // and instead rely on version bump label associated with this - // commit. - labels = labels.concat(pullRequest.labels - .filter(label => !Label.isCategory(label.name, "bump") && - !Label.isCategory(label.name, "scope")) - .map(label => label.name)); - // Check if the author of the Pull Request is part of the exclude list - if (pullRequest.user && - ((_c = (_b = config.changelog.exclude) === null || _b === void 0 ? void 0 : _b.authors) === null || _c === void 0 ? void 0 : _c.includes(pullRequest.user.login))) { - continue; - } - } } - // Check if any of the labels is part of the global exclusion list - if (labels.some(label => { var _a, _b; return (_b = (_a = config.changelog.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { + // Validate whether the commit matches any of the inclusion patterns + if (!labels + .concat([bumpLabel, "*"]) + .some(label => { var _a; return (_a = category.labels) === null || _a === void 0 ? void 0 : _a.includes(label); })) { continue; } - // Either group commits per Conventional Commit scope, or group them all - // together (*) - const scope = config.changelog.group === "scope" - ? ((_d = commit === null || commit === void 0 ? void 0 : commit.scope) === null || _d === void 0 ? void 0 : _d.toLowerCase()) || "*" - : "*"; - changelog.set(scope, (_e = changelog.get(scope)) !== null && _e !== void 0 ? _e : new Map()); - for (const category of config.changelog.categories) { - // Apply all exclusion patterns from Pull Request metadata on Category - if (labels.some(label => { var _a, _b; return (_b = (_a = category.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { - continue; - } - // Validate whether the commit matches any of the inclusion patterns - if (!labels - .concat([bumpLabel, "*"]) - .some(label => { var _a; return (_a = category.labels) === null || _a === void 0 ? void 0 : _a.includes(label); })) { - continue; - } - if (((_f = changelog.get(scope)) === null || _f === void 0 ? void 0 : _f.get(category.title)) === undefined) { - (_g = changelog.get(scope)) === null || _g === void 0 ? void 0 : _g.set(category.title, []); - } - (_j = (_h = changelog - .get(scope)) === null || _h === void 0 ? void 0 : _h.get(category.title)) === null || _j === void 0 ? void 0 : _j.push(yield generateChangelogEntry(commit)); - break; + if (((_f = changelog.get(scope)) === null || _f === void 0 ? void 0 : _f.get(category.title)) === undefined) { + (_g = changelog.get(scope)) === null || _g === void 0 ? void 0 : _g.set(category.title, []); } + (_j = (_h = changelog + .get(scope)) === null || _h === void 0 ? void 0 : _h.get(category.title)) === null || _j === void 0 ? void 0 : _j.push(await generateChangelogEntry(commit)); + break; } - // Sort changelog, with the all (*) scope always as last item - const sortedChangelog = [...changelog].sort((a, b) => a[0] === "*" ? 1 : b[0] === "*" ? -1 : a[0].localeCompare(b[0])); - // Generate Changelog - let formattedChangelog = "## What's changed\n"; - for (const [scope, categories] of sortedChangelog) { - const isGrouped = scope !== "*"; - if (isGrouped) { - formattedChangelog += `### ${capitalizeFirstLetter(scope)}\n`; - } - for (const [category, messages] of categories) { - if (messages.length > 0) { - formattedChangelog += isGrouped - ? `#### ${category}\n` - : `### ${category}\n`; - for (const message of messages) { - formattedChangelog += `* ${message}\n`; - } + } + // Sort changelog, with the all (*) scope always as last item + const sortedChangelog = [...changelog].sort((a, b) => a[0] === "*" ? 1 : b[0] === "*" ? -1 : a[0].localeCompare(b[0])); + // Generate Changelog + let formattedChangelog = "## What's changed\n"; + for (const [scope, categories] of sortedChangelog) { + const isGrouped = scope !== "*"; + if (isGrouped) { + formattedChangelog += `### ${capitalizeFirstLetter(scope)}\n`; + } + for (const [category, messages] of categories) { + if (messages.length > 0) { + formattedChangelog += isGrouped + ? `#### ${category}\n` + : `### ${category}\n`; + for (const message of messages) { + formattedChangelog += `* ${message}\n`; } } } - const { owner, repo } = github_1.context.repo; - const diffRange = `${startVersion}...${endVersion || github_1.context.sha.substring(0, 8)}`; - formattedChangelog += - `\n\n*Diff since last release: ` + - `[${diffRange}](https://github.com/${owner}/${repo}/compare/${diffRange})*`; - return formattedChangelog; - }); + } + const { owner, repo } = github_1.context.repo; + const diffRange = `${startVersion}...${endVersion || github_1.context.sha.substring(0, 8)}`; + formattedChangelog += + `\n\n*Diff since last release: ` + + `[${diffRange}](https://github.com/${owner}/${repo}/compare/${diffRange})*`; + return formattedChangelog; } exports.generateChangelogForCommits = generateChangelogForCommits; /** * Returns a markdown-formatted changelog, based on the info contained * in the provided `IVersionBumpTypeAndMessages`. */ -function generateChangelog(bump) { +async function generateChangelog(bump) { var _a, _b, _c, _d, _e; - return __awaiter(this, void 0, void 0, function* () { - return yield generateChangelogForCommits((_b = (_a = bump.foundVersion) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", (_e = (_d = (_c = bump.foundVersion) === null || _c === void 0 ? void 0 : _c.bump(bump.requiredBump, bump.initialDevelopment)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : "", bump.processedCommits - .map(c => c.message) - .filter(c => c)); - }); + return await generateChangelogForCommits((_b = (_a = bump.foundVersion) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", (_e = (_d = (_c = bump.foundVersion) === null || _c === void 0 ? void 0 : _c.bump(bump.requiredBump, bump.initialDevelopment)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : "", bump.processedCommits + .map(c => c.message) + .filter(c => c)); } exports.generateChangelog = generateChangelog; @@ -35134,11 +35078,7 @@ const VERSION_SCHEMES = ["semver", "sdkver"]; /** * This function takes two values and throws when their types don't match. */ -function verifyTypeMatches(name, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeToTest, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeItShouldBe) { +function verifyTypeMatches(name, typeToTest, typeItShouldBe) { if (typeof typeToTest !== typeof typeItShouldBe) { throw new Error(`Incorrect type '${typeof typeToTest}' for '${name}', must be '${typeof typeItShouldBe}'`); } @@ -35153,9 +35093,19 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } + setRuleActivationStatus(ruleId, enabled) { + const rule = this.rules.get(ruleId); + if (rule !== undefined) { + rule.enabled = enabled; + } + else { + core.warning(`Rule "${ruleId}" is unknown; enabling or disabling it has no effect.`); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any loadFromData(data) { - var _a, _b; - var _c; + var _a, _b, _c; + var _d; for (const key in data) { if (!CONFIG_ITEMS.includes(key)) { throw new Error(`Unknown configuration item '${key}' detected!`); @@ -35172,12 +35122,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - if (item in this.rules) { - this.rules[item].enabled = key === "enable"; - } - else { - core.warning(`Rule "${item}" is unknown; enabling or disabling it has no effect.`); - } + this.setRuleActivationStatus(item, key === "enable"); } } else { @@ -35214,20 +35159,24 @@ class Configuration { this.tags[typ] = { description: typeValue, bump: false }; break; case "object": - for (const entry of Object.keys(typeValue)) { - if (["description", "bump"].includes(entry)) { - if (entry === "description") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + { + const tagObject = (_a = this.tags[typ]) !== null && _a !== void 0 ? _a : {}; + for (const entry of Object.keys(typeValue)) { + if (["description", "bump"].includes(entry)) { + if (entry === "description") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + tagObject.description = typeValue[entry]; + } + else if (entry === "bump") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + tagObject.bump = typeValue[entry]; + } } - else if (entry === "bump") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + else { + core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } - this.tags[typ] = this.tags[typ] ? this.tags[typ] : {}; - this.tags[typ][entry] = typeValue[entry]; - } - else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } + this.tags[typ] = tagObject; } break; default: @@ -35246,11 +35195,11 @@ class Configuration { let desc = ""; // Use the default description if it's one of the default tags if (typ in DEFAULT_ACCEPTED_TAGS) { - desc = (_a = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _a !== void 0 ? _a : ""; + desc = (_b = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _b !== void 0 ? _b : ""; } this.tags[typ].description = desc; } - (_b = (_c = this.tags[typ]).bump) !== null && _b !== void 0 ? _b : (_c.bump = false); + (_c = (_d = this.tags[typ]).bump) !== null && _c !== void 0 ? _c : (_d.bump = false); } break; case "allowed-branches": @@ -35365,10 +35314,10 @@ class Configuration { this.rules = new Map(); this.sdkverCreateReleaseBranches = undefined; for (const rule of rules_1.ALL_RULES) { - this.rules[rule.id] = { + this.rules.set(rule.id, { description: rule.description, enabled: rule.default, - }; + }); } if (fs.existsSync(configPath)) { const data = yaml.parse(fs.readFileSync(configPath, "utf8")); @@ -35488,22 +35437,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __asyncValues = (this && this.__asyncValues) || function (o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.createBranch = exports.getCommitsBetweenRefs = exports.currentHeadMatchesTag = exports.getContent = exports.updateLabels = exports.getAssociatedPullRequests = exports.getLatestTags = exports.getShaForTag = exports.matchTagsToCommits = exports.getReleaseConfiguration = exports.getConfig = exports.createTag = exports.updateDraftRelease = exports.getRelease = exports.createRelease = exports.getPullRequest = exports.getCommitsInPR = exports.getPullRequestTitle = exports.getRunNumber = exports.getPullRequestId = exports.isPullRequestEvent = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -35554,10 +35487,8 @@ exports.getRunNumber = getRunNumber; /** * The current pull request's title */ -function getPullRequestTitle() { - return __awaiter(this, void 0, void 0, function* () { - return (yield getPullRequest(getPullRequestId())).title; - }); +async function getPullRequestTitle() { + return (await getPullRequest(getPullRequestId())).title; } exports.getPullRequestTitle = getPullRequestTitle; /** @@ -35565,12 +35496,13 @@ exports.getPullRequestTitle = getPullRequestTitle; * @param pullRequestId GitHub pull request ID * @returns ICommit[] List of ICommit objects */ -function getCommitsInPR(pullRequestId) { - return __awaiter(this, void 0, void 0, function* () { - // Retrieve commits from provided pull request - const { data: commits } = yield getOctokit().rest.pulls.listCommits(Object.assign(Object.assign({}, github.context.repo), { pull_number: pullRequestId })); - return githubCommitsAsICommits(commits); +async function getCommitsInPR(pullRequestId) { + // Retrieve commits from provided pull request + const { data: commits } = await getOctokit().rest.pulls.listCommits({ + ...github.context.repo, + pull_number: pullRequestId, }); + return githubCommitsAsICommits(commits); } exports.getCommitsInPR = getCommitsInPR; /** @@ -35578,11 +35510,12 @@ exports.getCommitsInPR = getCommitsInPR; * @param pullRequestId GitHub Pullrequest ID * @returns Pull Request */ -function getPullRequest(pullRequestId) { - return __awaiter(this, void 0, void 0, function* () { - const { data: pr } = yield getOctokit().rest.pulls.get(Object.assign(Object.assign({}, github.context.repo), { pull_number: pullRequestId })); - return pr; +async function getPullRequest(pullRequestId) { + const { data: pr } = await getOctokit().rest.pulls.get({ + ...github.context.repo, + pull_number: pullRequestId, }); + return pr; } exports.getPullRequest = getPullRequest; /** @@ -35592,11 +35525,15 @@ exports.getPullRequest = getPullRequest; * @param body The release's text description * @param draft Create this release as a 'draft' release */ -function createRelease(tagName, commitish, body, draft, prerelease) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.repos.createRelease(Object.assign(Object.assign({}, github.context.repo), { tag_name: tagName, target_commitish: commitish, name: tagName, body, - draft, - prerelease })); +async function createRelease(tagName, commitish, body, draft, prerelease) { + await getOctokit().rest.repos.createRelease({ + ...github.context.repo, + tag_name: tagName, + target_commitish: commitish, + name: tagName, + body, + draft, + prerelease, }); } exports.createRelease = createRelease; @@ -35608,50 +35545,50 @@ exports.createRelease = createRelease; * * Returns an object {id, name}, or `undefined` if no tag was found. */ -function getRelease(params) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`getRelease: finding ${params.draftOnly ? "draft " : ""}release with the prefix: ${params.prefixToMatch}`); - const octo = getOctokit(); - const result = (yield octo.paginate(octo.rest.repos.listReleases, Object.assign({}, github.context.repo))).map(r => ({ isDraft: r.draft, tagName: r.tag_name, id: r.id })); - core.debug(`getRelease: listReleases returned:\n${JSON.stringify(result)}`); - /** - * We need to: - * - only consider releases starting with the provided prefix, draft and - * release parameters - * - consider the major/minor constraint, if provided - * - _NOT_ rely on the temporal data; the precendence of the existing tags - * shall determined according to a "SemVer-esque prerelease", that is: - * * componentX-1.2.3-9 < componentX-1.2.3-10 - * - return the highest-precedence item - */ - const releaseList = result - .filter(r => r.isDraft === params.draftOnly) - .filter(r => { - const asSemVer = semver_1.SemVer.fromString(r.tagName); - return ((asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prefix) === params.prefixToMatch && - (params.fullReleasesOnly ? (asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prerelease) === "" : true)); - }) - .map(r => ({ id: r.id, name: r.tagName })) - .sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); - core.debug(`getRelease: sorted list of releases:\n${JSON.stringify(releaseList)}`); - if (params.constraint) { - // We're sorted by precedence, highest last, so let's reverse it and we can - // take the first major/minor version lower than the constraint we encounter. - releaseList.reverse(); - for (const r of releaseList) { - core.debug(`checking release ${r.name} against constraint ` + - `${params.constraint.major}.${params.constraint.minor}.*`); - const sv = semver_1.SemVer.fromString(r.name); - if (sv && - sv.major <= params.constraint.major && - sv.minor <= params.constraint.minor) { - return r; - } +async function getRelease(params) { + core.info(`getRelease: finding ${params.draftOnly ? "draft " : ""}release with the prefix: ${params.prefixToMatch}`); + const octo = getOctokit(); + const result = (await octo.paginate(octo.rest.repos.listReleases, { + ...github.context.repo, + })).map(r => ({ isDraft: r.draft, tagName: r.tag_name, id: r.id })); + core.debug(`getRelease: listReleases returned:\n${JSON.stringify(result)}`); + /** + * We need to: + * - only consider releases starting with the provided prefix, draft and + * release parameters + * - consider the major/minor constraint, if provided + * - _NOT_ rely on the temporal data; the precendence of the existing tags + * shall determined according to a "SemVer-esque prerelease", that is: + * * componentX-1.2.3-9 < componentX-1.2.3-10 + * - return the highest-precedence item + */ + const releaseList = result + .filter(r => r.isDraft === params.draftOnly) + .filter(r => { + const asSemVer = semver_1.SemVer.fromString(r.tagName); + return ((asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prefix) === params.prefixToMatch && + (params.fullReleasesOnly ? (asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prerelease) === "" : true)); + }) + .map(r => ({ id: r.id, name: r.tagName })) + .sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); + core.debug(`getRelease: sorted list of releases:\n${JSON.stringify(releaseList)}`); + if (params.constraint) { + // We're sorted by precedence, highest last, so let's reverse it and we can + // take the first major/minor version lower than the constraint we encounter. + releaseList.reverse(); + for (const r of releaseList) { + core.debug(`checking release ${r.name} against constraint ` + + `${params.constraint.major}.${params.constraint.minor}.*`); + const sv = semver_1.SemVer.fromString(r.name); + if (sv && + sv.major <= params.constraint.major && + sv.minor <= params.constraint.minor) { + return r; } - return; } - return releaseList.pop(); - }); + return; + } + return releaseList.pop(); } exports.getRelease = getRelease; /** @@ -35659,13 +35596,20 @@ exports.getRelease = getRelease; * * Returns `true` if successful */ -function updateDraftRelease(id, newName, tagName, sha, bodyContents, isDraft = true, isPrerelease = false) { - return __awaiter(this, void 0, void 0, function* () { - core.debug(`Update existing draft release with id ${id} to ${newName} (${tagName}) sha: ${sha}, ` + - `and body below:\n${bodyContents}`); - const result = yield getOctokit().rest.repos.updateRelease(Object.assign(Object.assign({}, github.context.repo), { release_id: id, target_commitish: sha, draft: isDraft, prerelease: isPrerelease, body: bodyContents, name: newName, tag_name: tagName })); - return result.status < 400; +async function updateDraftRelease(id, newName, tagName, sha, bodyContents, isDraft = true, isPrerelease = false) { + core.debug(`Update existing draft release with id ${id} to ${newName} (${tagName}) sha: ${sha}, ` + + `and body below:\n${bodyContents}`); + const result = await getOctokit().rest.repos.updateRelease({ + ...github.context.repo, + release_id: id, + target_commitish: sha, + draft: isDraft, + prerelease: isPrerelease, + body: bodyContents, + name: newName, + tag_name: tagName, }); + return result.status < 400; } exports.updateDraftRelease = updateDraftRelease; /** @@ -35673,9 +35617,11 @@ exports.updateDraftRelease = updateDraftRelease; * @param tagName Name of the tag * @param sha The SHA1 value of the tag */ -function createTag(tagName, sha) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.git.createRef(Object.assign(Object.assign({}, github.context.repo), { ref: tagName.startsWith("refs/tags/") ? tagName : `refs/tags/${tagName}`, sha })); +async function createTag(tagName, sha) { + await getOctokit().rest.git.createRef({ + ...github.context.repo, + ref: tagName.startsWith("refs/tags/") ? tagName : `refs/tags/${tagName}`, + sha, }); } exports.createTag = createTag; @@ -35683,29 +35629,25 @@ exports.createTag = createTag; * Downloads the requested configuration file in case it exists. * @param path Path towards the Commisery configuration file */ -function getConfig(path) { - return __awaiter(this, void 0, void 0, function* () { - const config = yield getContent(path); - if (config !== undefined) { - fs.writeFileSync(".commisery.yml", config); - } - }); +async function getConfig(path) { + const config = await getContent(path); + if (config !== undefined) { + fs.writeFileSync(".commisery.yml", config); + } } exports.getConfig = getConfig; /** * Downloads the release configuration (.github/release.y[a]ml) in the repository. * Return empty configuration if the file(s) do not exist. */ -function getReleaseConfiguration() { - return __awaiter(this, void 0, void 0, function* () { - for (const path of [".github/release.yml", ".github/release.yaml"]) { - const content = yield getContent(path); - if (content !== undefined) { - return content; - } +async function getReleaseConfiguration() { + for (const path of [".github/release.yml", ".github/release.yaml"]) { + const content = await getContent(path); + if (content !== undefined) { + return content; } - return ""; - }); + } + return ""; } exports.getReleaseConfiguration = getReleaseConfiguration; /** @@ -35719,55 +35661,37 @@ exports.getReleaseConfiguration = getReleaseConfiguration; * Alternatively, if no match could be made, returns `null` along with all * the commits encountered. */ -function matchTagsToCommits(sha, matcher) { - var _a, e_1, _b, _c; - return __awaiter(this, void 0, void 0, function* () { - const octo = getOctokit(); - const commitList = []; - let match = null; - sha = sha !== null && sha !== void 0 ? sha : github.context.sha; - try { - for (var _d = true, _e = __asyncValues(octo.paginate.iterator(octo.rest.repos.listCommits, Object.assign(Object.assign({}, github.context.repo), { sha }))), _f; _f = yield _e.next(), _a = _f.done, !_a;) { - _c = _f.value; - _d = false; - try { - const resp = _c; - for (const commit of resp.data) { - match = matcher(commit.commit.message, commit.sha); - if (match) { - core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); - return [match, commitList]; - } - commitList.push({ message: commit.commit.message, sha: commit.sha }); - } - } - finally { - _d = true; - } +async function matchTagsToCommits(sha, matcher) { + const octo = getOctokit(); + const commitList = []; + let match = null; + sha = sha !== null && sha !== void 0 ? sha : github.context.sha; + for await (const resp of octo.paginate.iterator(octo.rest.repos.listCommits, { + ...github.context.repo, + sha, + })) { + for (const commit of resp.data) { + match = matcher(commit.commit.message, commit.sha); + if (match) { + core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); + return [match, commitList]; } + commitList.push({ message: commit.commit.message, sha: commit.sha }); } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (!_d && !_a && (_b = _e.return)) yield _b.call(_e); - } - finally { if (e_1) throw e_1.error; } - } - return [match, commitList]; - }); + } + return [match, commitList]; } exports.matchTagsToCommits = matchTagsToCommits; /** * Get the commit sha associated with the provided tag, or `undefined` if * the tag doesn't exist. */ -function getShaForTag(tag) { +async function getShaForTag(tag) { var _a; - return __awaiter(this, void 0, void 0, function* () { - if (!tag.startsWith("refs/tags/")) { - tag = `refs/tags/${tag}`; - } - const result = yield getOctokit().graphql(` + if (!tag.startsWith("refs/tags/")) { + tag = `refs/tags/${tag}`; + } + const result = await getOctokit().graphql(` { repository(owner: "${github.context.repo.owner}", name: "${github.context.repo.repo}") { ref(qualifiedName: "${tag}") { @@ -35778,16 +35702,14 @@ function getShaForTag(tag) { } } `); - return (_a = result.repository.ref) === null || _a === void 0 ? void 0 : _a.target.oid; - }); + return (_a = result.repository.ref) === null || _a === void 0 ? void 0 : _a.target.oid; } exports.getShaForTag = getShaForTag; /** * Retrieve `pageSize` tags in the current repo */ -function getLatestTags(pageSize) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield getOctokit().graphql(` +async function getLatestTags(pageSize) { + const result = await getOctokit().graphql(` { repository(owner: "${github.context.repo.owner}", name: "${github.context.repo.repo}") { refs( @@ -35812,96 +35734,107 @@ function getLatestTags(pageSize) { } } `); - const tagList = result.repository.refs.edges.map(x => ({ - name: x.node.name, - commitSha: x.node.reftarget.tagtarget - ? x.node.reftarget.tagtarget.commitsha - : x.node.reftarget.commitsha, - })); - return tagList; - }); + const tagList = result.repository.refs.edges.map(x => ({ + name: x.node.name, + commitSha: x.node.reftarget.tagtarget + ? x.node.reftarget.tagtarget.commitsha + : x.node.reftarget.commitsha, + })); + return tagList; } exports.getLatestTags = getLatestTags; /** * Retrieve the Pull Requests associated with the specified commit SHA */ -function getAssociatedPullRequests(sha) { - return __awaiter(this, void 0, void 0, function* () { - try { - const { data: prs } = yield getOctokit().rest.repos.listPullRequestsAssociatedWithCommit(Object.assign(Object.assign({}, github.context.repo), { commit_sha: sha })); - return prs; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } - catch (error) { - if (error.message !== "Resource not accessible by integration") { - throw error; - } +async function getAssociatedPullRequests(sha) { + try { + const { data: prs } = await getOctokit().rest.repos.listPullRequestsAssociatedWithCommit({ + ...github.context.repo, + commit_sha: sha, + }); + return prs; + } + catch (error) { + if (error instanceof Error && + error.message === "Resource not accessible by integration") { return []; } - }); + throw error; + } } exports.getAssociatedPullRequests = getAssociatedPullRequests; /** * Updates the Pull Request (issue) labels */ -function updateLabels(labels) { - return __awaiter(this, void 0, void 0, function* () { - const issueId = getPullRequestId(); - // Retrieve current labels - const { data: pullRequestLabels } = yield getOctokit().rest.issues.listLabelsOnIssue(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId })); - try { - // Remove all bump, type and initial development labels - for (const label of pullRequestLabels) { - if (Label.isManaged(label.name)) { - // Check if the label should remain, if not, remove the label from the Pull Request - if (labels.includes(label.name)) { - labels = labels.filter(l => l !== label.name); - } - else { - yield getOctokit().rest.issues.removeLabel(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId, name: label.name })); - } +async function updateLabels(labels) { + const issueId = getPullRequestId(); + // Retrieve current labels + const { data: pullRequestLabels } = await getOctokit().rest.issues.listLabelsOnIssue({ + ...github.context.repo, + issue_number: issueId, + }); + try { + // Remove all bump, type and initial development labels + for (const label of pullRequestLabels) { + if (Label.isManaged(label.name)) { + // Check if the label should remain, if not, remove the label from the Pull Request + if (labels.includes(label.name)) { + labels = labels.filter(l => l !== label.name); + } + else { + await getOctokit().rest.issues.removeLabel({ + ...github.context.repo, + issue_number: issueId, + name: label.name, + }); } } - if (labels.length > 0) { - // Add new label if it does not yet exist - yield getOctokit().rest.issues.addLabels(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId, labels })); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any } - catch (error) { - if (error.message !== "Resource not accessible by integration") { - throw error; - } + if (labels.length > 0) { + // Add new label if it does not yet exist + await getOctokit().rest.issues.addLabels({ + ...github.context.repo, + issue_number: issueId, + labels, + }); + } + } + catch (error) { + if (error instanceof Error && + error.message === "Resource not accessible by integration") { core.warning("Unable to update Pull Request labels, did you provide the `write` permission for `issues` and `pull-requests`?"); + return; } - }); + throw error; + } } exports.updateLabels = updateLabels; /** * Downloads and returns the contents of the specified file path. */ -function getContent(path) { - return __awaiter(this, void 0, void 0, function* () { - try { - const response = yield getOctokit().rest.repos.getContent(Object.assign(Object.assign({}, github.context.repo), { path, ref: github.context.ref })); - if ("content" in response.data) { - return Buffer.from(response.data.content, "base64").toString("utf8"); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } - catch (error) { - core.debug(error.message); +async function getContent(path) { + try { + const response = await getOctokit().rest.repos.getContent({ + ...github.context.repo, + path, + ref: github.context.ref, + }); + if ("content" in response.data) { + return Buffer.from(response.data.content, "base64").toString("utf8"); } - }); + } + catch (error) { + // We intentially capture all failures and return `undefined` in case the + // file does not exist or cannot be accessed. + core.debug(error.message); + } } exports.getContent = getContent; /** * Returns `true` if `context.sha` matches the sha of the tag `tagName`. */ -function currentHeadMatchesTag(tagName) { - return __awaiter(this, void 0, void 0, function* () { - return (yield getShaForTag(tagName)) === github.context.sha; - }); +async function currentHeadMatchesTag(tagName) { + return (await getShaForTag(tagName)) === github.context.sha; } exports.currentHeadMatchesTag = currentHeadMatchesTag; /** @@ -35911,11 +35844,12 @@ exports.currentHeadMatchesTag = currentHeadMatchesTag; * * Returns a list ICommits representing `baseRef...compRef`. */ -function getCommitsBetweenRefs(baseRef, compRef) { - return __awaiter(this, void 0, void 0, function* () { - const { data: resp } = yield getOctokit().rest.repos.compareCommitsWithBasehead(Object.assign(Object.assign({}, github.context.repo), { basehead: `${baseRef}...${compRef !== null && compRef !== void 0 ? compRef : github.context.sha}` })); - return githubCommitsAsICommits(resp.commits); +async function getCommitsBetweenRefs(baseRef, compRef) { + const { data: resp } = await getOctokit().rest.repos.compareCommitsWithBasehead({ + ...github.context.repo, + basehead: `${baseRef}...${compRef !== null && compRef !== void 0 ? compRef : github.context.sha}`, }); + return githubCommitsAsICommits(resp.commits); } exports.getCommitsBetweenRefs = getCommitsBetweenRefs; /** @@ -35923,9 +35857,11 @@ exports.getCommitsBetweenRefs = getCommitsBetweenRefs; * @param name The name of the branch to be created * @param sha The commit hash of the branch-off point */ -function createBranch(name, sha) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.git.createRef(Object.assign(Object.assign({}, github.context.repo), { ref: name.startsWith("refs/heads/") ? name : `refs/heads/${name}`, sha })); +async function createBranch(name, sha) { + await getOctokit().rest.git.createRef({ + ...github.context.repo, + ref: name.startsWith("refs/heads/") ? name : `refs/heads/${name}`, + sha, }); } exports.createBranch = createBranch; @@ -36010,7 +35946,7 @@ var LlvmLevel; LlvmLevel["ERROR"] = "ERROR"; LlvmLevel["WARNING"] = "WARNING"; LlvmLevel["NOTE"] = "NOTE"; -})(LlvmLevel = exports.LlvmLevel || (exports.LlvmLevel = {})); +})(LlvmLevel || (exports.LlvmLevel = LlvmLevel = {})); // eslint-disable-next-line no-shadow var TextFormat; (function (TextFormat) { @@ -36163,8 +36099,8 @@ const logging_1 = __nccwpck_require__(1517); */ function validateRules(message, config) { const errors = []; - const disabledRules = Object.entries(config.rules) - .filter(item => !item[1]["enabled"]) + const disabledRules = Array.from(config.rules) + .filter(item => item[1].enabled === false) .map(item => item[0]); for (const rule of exports.ALL_RULES) { try { @@ -36175,10 +36111,9 @@ function validateRules(message, config) { catch (error) { if (error instanceof logging_1.LlvmError) { errors.push(error); + continue; } - else { - throw error; - } + throw error; } } return errors; @@ -36899,7 +36834,7 @@ var SemVerType; SemVerType[SemVerType["PATCH"] = 1] = "PATCH"; SemVerType[SemVerType["MINOR"] = 2] = "MINOR"; SemVerType[SemVerType["MAJOR"] = 3] = "MAJOR"; -})(SemVerType = exports.SemVerType || (exports.SemVerType = {})); +})(SemVerType || (exports.SemVerType = SemVerType = {})); class SemVer { constructor({ major, minor, patch, prerelease = "", build = "", prefix = "", }) { this.major = major; @@ -36910,7 +36845,10 @@ class SemVer { this.prefix = prefix; } static copy(semver) { - return new SemVer(Object.assign({ build: semver.build }, semver)); + return new SemVer({ + build: semver.build, + ...semver, + }); } get build() { return this._build; @@ -37180,15 +37118,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validatePrTitleBump = exports.validatePrTitle = exports.validateCommitsInCurrentPR = exports.processCommits = exports.outputCommitListErrors = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -37268,11 +37197,13 @@ function processCommits(commits, config) { message: undefined, errors: error.errors, }); + continue; } else if (error instanceof errors_1.MergeCommitError || error instanceof errors_1.FixupCommitError) { continue; } + throw error; } } return results; @@ -37281,128 +37212,121 @@ exports.processCommits = processCommits; /** * Validates all commit messages in the current pull request. */ -function validateCommitsInCurrentPR(config) { +async function validateCommitsInCurrentPR(config) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const commits = yield (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); - const results = processCommits(commits, config); - const passResults = results.filter(c => c.errors.length === 0); - const failResults = results.filter(c => c.errors.length !== 0); - if (passResults.length > 0) { - core.info(`✅ ${failResults.length === 0 ? "All " : ""}${passResults.length}` + - ` of the pull request's commits are valid Conventional Commits`); - for (const c of passResults) { - core.startGroup(`✅ Commit (${c.input.sha.slice(0, 8)}): ${(_a = c.message) === null || _a === void 0 ? void 0 : _a.subject}`); - core.info(c.input.message); - core.endGroup(); - } - } - if (failResults.length > 0) { - core.info(""); // for vertical whitespace - core.setFailed(`${failResults.length} of the pull request's commits are not valid Conventional Commits`); - outputCommitListErrors(failResults, true); + const commits = await (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); + const results = processCommits(commits, config); + const passResults = results.filter(c => c.errors.length === 0); + const failResults = results.filter(c => c.errors.length !== 0); + if (passResults.length > 0) { + core.info(`✅ ${failResults.length === 0 ? "All " : ""}${passResults.length}` + + ` of the pull request's commits are valid Conventional Commits`); + for (const c of passResults) { + core.startGroup(`✅ Commit (${c.input.sha.slice(0, 8)}): ${(_a = c.message) === null || _a === void 0 ? void 0 : _a.subject}`); + core.info(c.input.message); + core.endGroup(); } - return { - compliant: failResults.length === 0, - messages: passResults.map(r => r.message), - }; - }); + } + if (failResults.length > 0) { + core.info(""); // for vertical whitespace + core.setFailed(`${failResults.length} of the pull request's commits are not valid Conventional Commits`); + outputCommitListErrors(failResults, true); + } + return { + compliant: failResults.length === 0, + messages: passResults.map(r => r.message), + }; } exports.validateCommitsInCurrentPR = validateCommitsInCurrentPR; /** * Validates the pull request title and, if compliant, returns it as a * ConventionalCommitMessage object. */ -function validatePrTitle(_) { - return __awaiter(this, void 0, void 0, function* () { - const prTitleText = yield (0, github_1.getPullRequestTitle)(); - let errors = []; - let conventionalCommitMessage; - core.info(""); // for vertical whitespace - let errorMessage = "The pull request title is not compliant " + - "with the Conventional Commits specification"; - try { - conventionalCommitMessage = new commit_1.ConventionalCommitMessage(prTitleText); - } - catch (error) { - if (error instanceof errors_1.ConventionalCommitError) { - errors = error.errors; - } - else { - if (error instanceof errors_1.MergeCommitError) { - errorMessage = `${errorMessage} (it describes a merge commit)`; - } - else if (error instanceof errors_1.FixupCommitError) { - errorMessage = `${errorMessage} (it describes a fixup commit)`; - } - core.setFailed(errorMessage); - return undefined; - } +async function validatePrTitle(_) { + const prTitleText = await (0, github_1.getPullRequestTitle)(); + let errors = []; + let conventionalCommitMessage; + core.info(""); // for vertical whitespace + let errorMessage = "The pull request title is not compliant " + + "with the Conventional Commits specification"; + try { + conventionalCommitMessage = new commit_1.ConventionalCommitMessage(prTitleText); + } + catch (error) { + if (error instanceof errors_1.ConventionalCommitError) { + errors = error.errors; } - if (errors.length > 0) { + else if (error instanceof errors_1.MergeCommitError || + error instanceof errors_1.FixupCommitError) { + errorMessage = `${errorMessage} (it describes a ${error instanceof errors_1.MergeCommitError ? "merge" : "fixup"} commit)`; core.setFailed(errorMessage); - outputCommitErrors(prTitleText, errors, undefined, true); + return undefined; } else { - core.startGroup(`✅ The pull request title is compliant with the Conventional Commits specification`); - core.info(prTitleText); - core.endGroup(); + throw error; } - return conventionalCommitMessage; - }); + } + if (errors.length > 0) { + core.setFailed(errorMessage); + outputCommitErrors(prTitleText, errors, undefined, true); + } + else { + core.startGroup(`✅ The pull request title is compliant with the Conventional Commits specification`); + core.info(prTitleText); + core.endGroup(); + } + return conventionalCommitMessage; } exports.validatePrTitle = validatePrTitle; /** * Validates bump level consistency between the PR title and its commits. * This implies that the PR title must comply with the Conventional Commits spec. */ -function validatePrTitleBump(config) { +async function validatePrTitleBump(config) { var _a, _b; - return __awaiter(this, void 0, void 0, function* () { - const prTitleText = yield (0, github_1.getPullRequestTitle)(); - const commits = yield (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); - const prTitle = yield validatePrTitle(config); - const baseError = "Cannot validate the consistency of bump levels between PR title and PR commits"; - if (prTitle === undefined) { - core.warning(`${baseError}, as PR title is not a valid Conventional Commits message.`); - return false; - } - if (commits.length === 0) { - core.warning("No commits found in this pull request."); - return true; - } - core.info(""); // for vertical whitespace - const results = processCommits(commits, config); - if (results.some(c => c.errors.length !== 0)) { - // Abort if the list contains any non-compliant commits; bump level - // validation only really makes sense if all commits are found to - // be compliant. - core.warning(`${baseError}, as the PR contains non-compliant commits`); - return false; - } - const highestBump = (_b = (_a = results.reduce((acc, val) => { - var _a, _b, _c, _d; - const accb = (_b = (_a = acc.message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; - const valb = (_d = (_c = val.message) === null || _c === void 0 ? void 0 : _c.bump) !== null && _d !== void 0 ? _d : semver_1.SemVerType.NONE; - return accb > valb ? acc : val; - }).message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; - if (highestBump !== prTitle.bump) { - const commitSubjects = results - .map(r => { var _a; return (_a = r.message) === null || _a === void 0 ? void 0 : _a.subject; }) - .filter(x => x !== undefined); - core.setFailed("The PR title's bump level is not consistent with its commits.\n" + - `The PR title type ${prTitle.type} represents bump level ` + - `${semver_1.SemVerType[prTitle.bump]}, while the highest bump in the ` + - `commits is ${semver_1.SemVerType[highestBump]}.\n` + - `PR title: "${prTitleText}"\n` + - `Commit list:\n${` - ${commitSubjects.join("\n - ")}`}`); - return false; - } - else { - core.info(`✅ The pull request title's bump level is consistent with the PR's commits`); - return true; - } - }); + const prTitleText = await (0, github_1.getPullRequestTitle)(); + const commits = await (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); + const prTitle = await validatePrTitle(config); + const baseError = "Cannot validate the consistency of bump levels between PR title and PR commits"; + if (prTitle === undefined) { + core.warning(`${baseError}, as PR title is not a valid Conventional Commits message.`); + return false; + } + if (commits.length === 0) { + core.warning("No commits found in this pull request."); + return true; + } + core.info(""); // for vertical whitespace + const results = processCommits(commits, config); + if (results.some(c => c.errors.length !== 0)) { + // Abort if the list contains any non-compliant commits; bump level + // validation only really makes sense if all commits are found to + // be compliant. + core.warning(`${baseError}, as the PR contains non-compliant commits`); + return false; + } + const highestBump = (_b = (_a = results.reduce((acc, val) => { + var _a, _b, _c, _d; + const accb = (_b = (_a = acc.message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; + const valb = (_d = (_c = val.message) === null || _c === void 0 ? void 0 : _c.bump) !== null && _d !== void 0 ? _d : semver_1.SemVerType.NONE; + return accb > valb ? acc : val; + }).message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; + if (highestBump !== prTitle.bump) { + const commitSubjects = results + .map(r => { var _a; return (_a = r.message) === null || _a === void 0 ? void 0 : _a.subject; }) + .filter(x => x !== undefined); + core.setFailed("The PR title's bump level is not consistent with its commits.\n" + + `The PR title type ${prTitle.type} represents bump level ` + + `${semver_1.SemVerType[prTitle.bump]}, while the highest bump in the ` + + `commits is ${semver_1.SemVerType[highestBump]}.\n` + + `PR title: "${prTitleText}"\n` + + `Commit list:\n${` - ${commitSubjects.join("\n - ")}`}`); + return false; + } + else { + core.info(`✅ The pull request title's bump level is consistent with the PR's commits`); + return true; + } } exports.validatePrTitleBump = validatePrTitleBump; @@ -47737,12 +47661,33 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"] /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; /******/ /************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module is referenced by other modules so it can't be inlined -/******/ var __webpack_exports__ = __nccwpck_require__(1745); -/******/ module.exports = __webpack_exports__; -/******/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; +var exports = __webpack_exports__; + +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +const bump_1 = __nccwpck_require__(1745); +(0, bump_1.run)(); + +})(); + +module.exports = __webpack_exports__; /******/ })() ; \ No newline at end of file diff --git a/dist/cli/index.js b/dist/cli/index.js index 37adf63b..5504d10e 100755 --- a/dist/cli/index.js +++ b/dist/cli/index.js @@ -32304,15 +32304,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; @@ -32344,7 +32335,7 @@ program - a file containing the commit message to check - a revision range that \`git rev-list\` can interpret When TARGET is omitted, 'HEAD' is implied.`) - .action((target) => __awaiter(void 0, void 0, void 0, function* () { + .action(async (target) => { const config = new config_1.Configuration(program.opts().config); if (target.length === 0) { target = ["HEAD"]; @@ -32354,7 +32345,7 @@ program messages = [fs.readFileSync(target.join(" "), "utf8")]; } else { - messages = yield (0, utils_1.getCommitMessages)(target); + messages = await (0, utils_1.getCommitMessages)(target); } for (const message of messages) { try { @@ -32365,14 +32356,17 @@ program for (const err of error.errors) { core.info(err.report()); } + continue; } + throw error; } } -})); +}); program .command("overview") .description("Lists the accepted Conventional Commit types and Rules (including description)") .action(() => { + var _a, _b; const config = new config_1.Configuration(program.opts().config); core.info((0, dedent_1.default)(` Conventional Commit types @@ -32391,10 +32385,10 @@ program `)); core.info(os.EOL); for (const rule in config.rules) { - const status = config.rules[rule].enabled + const status = ((_a = config.rules.get(rule)) === null || _a === void 0 ? void 0 : _a.enabled) ? `${green}o${reset}` : `${red}x${reset}`; - core.info(`[${status}] ${rule}: ${gray}${config.rules[rule].description}${reset}`); + core.info(`[${status}] ${rule}: ${gray}${(_b = config.rules.get(rule)) === null || _b === void 0 ? void 0 : _b.description}${reset}`); } }); program.parse(); @@ -32403,7 +32397,7 @@ program.parse(); /***/ }), /***/ 2449: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -32422,15 +32416,6 @@ program.parse(); * See the License for the specific language governing permissions and * limitations under the License. */ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getCommitMessages = exports.getRootPath = void 0; const simple_git_1 = __nccwpck_require__(9103); @@ -32438,69 +32423,65 @@ let __ROOT_PATH = undefined; /** * Determine the root path of the GIT project */ -function getRootPath() { - return __awaiter(this, void 0, void 0, function* () { - if (__ROOT_PATH === undefined) { - try { - __ROOT_PATH = yield (0, simple_git_1.simpleGit)().revparse({ "--show-toplevel": null }); - } - catch (GitError) { +async function getRootPath() { + if (__ROOT_PATH === undefined) { + try { + __ROOT_PATH = await (0, simple_git_1.simpleGit)().revparse({ "--show-toplevel": null }); + } + catch (error) { + if (error instanceof simple_git_1.GitError) { __ROOT_PATH = process.cwd(); } + else { + throw error; + } } - return __ROOT_PATH; - }); + } + return __ROOT_PATH; } exports.getRootPath = getRootPath; /** * Determines a list of commit hashes (based on `git rev-parse`) using the * provided target */ -function getCommitHashes(target) { - return __awaiter(this, void 0, void 0, function* () { - return (yield (0, simple_git_1.simpleGit)(yield getRootPath()).revparse(target)).split("\n"); - }); +async function getCommitHashes(target) { + return (await (0, simple_git_1.simpleGit)(await getRootPath()).revparse(target)).split("\n"); } /** * Retrieve the full commit message for the provided target */ -function getCommitMessage(target) { - return __awaiter(this, void 0, void 0, function* () { - return yield (0, simple_git_1.simpleGit)(yield getRootPath()).show([ - "-q", - "--format=%B", - target, - "--", - ]); - }); +async function getCommitMessage(target) { + return await (0, simple_git_1.simpleGit)(await getRootPath()).show([ + "-q", + "--format=%B", + target, + "--", + ]); } /** * Retrieves a list of commit messages based on the provided target * parameter */ -function getCommitMessages(target) { - return __awaiter(this, void 0, void 0, function* () { - const git = (0, simple_git_1.simpleGit)(yield getRootPath()); - let commitHashes = []; - if (/^[0-9a-fA-F]{40}$/.test(target.join(" ")) === false && - (yield getCommitHashes(target)).length > 1) { - commitHashes = (yield git.raw(["rev-list"].concat(target).concat(["--"]))).split("\n"); - } - else { - commitHashes.push(target[0]); +async function getCommitMessages(target) { + const git = (0, simple_git_1.simpleGit)(await getRootPath()); + let commitHashes = []; + if (/^[0-9a-fA-F]{40}$/.test(target.join(" ")) === false && + (await getCommitHashes(target)).length > 1) { + commitHashes = (await git.raw(["rev-list"].concat(target).concat(["--"]))).split("\n"); + } + else { + commitHashes.push(target[0]); + } + const messages = []; + for (const hash of commitHashes) { + try { + messages.push(await getCommitMessage(hash)); } - const messages = []; - for (const hash of commitHashes) { - try { - messages.push(yield getCommitMessage(hash)); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } - catch (error) { - continue; - } + catch (error) { + continue; } - return messages; - }); + } + return messages; } exports.getCommitMessages = getCommitMessages; @@ -32831,11 +32812,7 @@ const VERSION_SCHEMES = ["semver", "sdkver"]; /** * This function takes two values and throws when their types don't match. */ -function verifyTypeMatches(name, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeToTest, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeItShouldBe) { +function verifyTypeMatches(name, typeToTest, typeItShouldBe) { if (typeof typeToTest !== typeof typeItShouldBe) { throw new Error(`Incorrect type '${typeof typeToTest}' for '${name}', must be '${typeof typeItShouldBe}'`); } @@ -32850,9 +32827,19 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } + setRuleActivationStatus(ruleId, enabled) { + const rule = this.rules.get(ruleId); + if (rule !== undefined) { + rule.enabled = enabled; + } + else { + core.warning(`Rule "${ruleId}" is unknown; enabling or disabling it has no effect.`); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any loadFromData(data) { - var _a, _b; - var _c; + var _a, _b, _c; + var _d; for (const key in data) { if (!CONFIG_ITEMS.includes(key)) { throw new Error(`Unknown configuration item '${key}' detected!`); @@ -32869,12 +32856,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - if (item in this.rules) { - this.rules[item].enabled = key === "enable"; - } - else { - core.warning(`Rule "${item}" is unknown; enabling or disabling it has no effect.`); - } + this.setRuleActivationStatus(item, key === "enable"); } } else { @@ -32911,20 +32893,24 @@ class Configuration { this.tags[typ] = { description: typeValue, bump: false }; break; case "object": - for (const entry of Object.keys(typeValue)) { - if (["description", "bump"].includes(entry)) { - if (entry === "description") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + { + const tagObject = (_a = this.tags[typ]) !== null && _a !== void 0 ? _a : {}; + for (const entry of Object.keys(typeValue)) { + if (["description", "bump"].includes(entry)) { + if (entry === "description") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + tagObject.description = typeValue[entry]; + } + else if (entry === "bump") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + tagObject.bump = typeValue[entry]; + } } - else if (entry === "bump") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + else { + core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } - this.tags[typ] = this.tags[typ] ? this.tags[typ] : {}; - this.tags[typ][entry] = typeValue[entry]; - } - else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } + this.tags[typ] = tagObject; } break; default: @@ -32943,11 +32929,11 @@ class Configuration { let desc = ""; // Use the default description if it's one of the default tags if (typ in DEFAULT_ACCEPTED_TAGS) { - desc = (_a = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _a !== void 0 ? _a : ""; + desc = (_b = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _b !== void 0 ? _b : ""; } this.tags[typ].description = desc; } - (_b = (_c = this.tags[typ]).bump) !== null && _b !== void 0 ? _b : (_c.bump = false); + (_c = (_d = this.tags[typ]).bump) !== null && _c !== void 0 ? _c : (_d.bump = false); } break; case "allowed-branches": @@ -33062,10 +33048,10 @@ class Configuration { this.rules = new Map(); this.sdkverCreateReleaseBranches = undefined; for (const rule of rules_1.ALL_RULES) { - this.rules[rule.id] = { + this.rules.set(rule.id, { description: rule.description, enabled: rule.default, - }; + }); } if (fs.existsSync(configPath)) { const data = yaml.parse(fs.readFileSync(configPath, "utf8")); @@ -33171,7 +33157,7 @@ var LlvmLevel; LlvmLevel["ERROR"] = "ERROR"; LlvmLevel["WARNING"] = "WARNING"; LlvmLevel["NOTE"] = "NOTE"; -})(LlvmLevel = exports.LlvmLevel || (exports.LlvmLevel = {})); +})(LlvmLevel || (exports.LlvmLevel = LlvmLevel = {})); // eslint-disable-next-line no-shadow var TextFormat; (function (TextFormat) { @@ -33324,8 +33310,8 @@ const logging_1 = __nccwpck_require__(1517); */ function validateRules(message, config) { const errors = []; - const disabledRules = Object.entries(config.rules) - .filter(item => !item[1]["enabled"]) + const disabledRules = Array.from(config.rules) + .filter(item => item[1].enabled === false) .map(item => item[0]); for (const rule of exports.ALL_RULES) { try { @@ -33336,10 +33322,9 @@ function validateRules(message, config) { catch (error) { if (error instanceof logging_1.LlvmError) { errors.push(error); + continue; } - else { - throw error; - } + throw error; } } return errors; @@ -34060,7 +34045,7 @@ var SemVerType; SemVerType[SemVerType["PATCH"] = 1] = "PATCH"; SemVerType[SemVerType["MINOR"] = 2] = "MINOR"; SemVerType[SemVerType["MAJOR"] = 3] = "MAJOR"; -})(SemVerType = exports.SemVerType || (exports.SemVerType = {})); +})(SemVerType || (exports.SemVerType = SemVerType = {})); class SemVer { constructor({ major, minor, patch, prerelease = "", build = "", prefix = "", }) { this.major = major; @@ -34071,7 +34056,10 @@ class SemVer { this.prefix = prefix; } static copy(semver) { - return new SemVer(Object.assign({ build: semver.build }, semver)); + return new SemVer({ + build: semver.build, + ...semver, + }); } get build() { return this._build; diff --git a/dist/validate/index.js b/dist/validate/index.js index 318287a9..84fe78f9 100644 --- a/dist/validate/index.js +++ b/dist/validate/index.js @@ -33641,17 +33641,8 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.exportedForTesting = void 0; +exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); const bump_1 = __nccwpck_require__(1692); const config_1 = __nccwpck_require__(6373); @@ -33662,59 +33653,58 @@ const validate_1 = __nccwpck_require__(4953); /** * Determine labels to add based on the provided conventional commits */ -function determineLabels(conventionalCommits, config) { - return __awaiter(this, void 0, void 0, function* () { - const highestBumpType = (0, bump_1.getVersionBumpType)(conventionalCommits); - if (highestBumpType === semver_1.SemVerType.NONE) { - return []; +async function determineLabels(conventionalCommits, config) { + const highestBumpType = (0, bump_1.getVersionBumpType)(conventionalCommits); + if (highestBumpType === semver_1.SemVerType.NONE) { + return []; + } + const labels = []; + if (config.initialDevelopment) { + labels.push(Label.create("initial development")); + } + labels.push(Label.create("bump", semver_1.SemVerType[highestBumpType])); + return labels; +} +/** + * Validate action entrypoint + * + * Validates commits agains the Conventional Commits specification. + * @internal + */ +async function run() { + try { + if (!(0, github_1.isPullRequestEvent)()) { + core.warning("Conventional Commit Message validation requires a workflow using the `pull_request` trigger!"); + return; } - const labels = []; - if (config.initialDevelopment) { - labels.push(Label.create("initial development")); + await (0, github_1.getConfig)(core.getInput("config")); + const config = new config_1.Configuration(".commisery.yml"); + let compliant = true; + if (core.getBooleanInput("validate-commits")) { + // Validate the current PR's commit messages + const result = await (0, validate_1.validateCommitsInCurrentPR)(config); + compliant && (compliant = result.compliant); + await (0, github_1.updateLabels)(await determineLabels(result.messages, config)); } - labels.push(Label.create("bump", semver_1.SemVerType[highestBumpType])); - return labels; - }); -} -function run() { - return __awaiter(this, void 0, void 0, function* () { - try { - if (!(0, github_1.isPullRequestEvent)()) { - core.warning("Conventional Commit Message validation requires a workflow using the `pull_request` trigger!"); - return; - } - yield (0, github_1.getConfig)(core.getInput("config")); - const config = new config_1.Configuration(".commisery.yml"); - let compliant = true; - if (core.getBooleanInput("validate-commits")) { - // Validate the current PR's commit messages - const result = yield (0, validate_1.validateCommitsInCurrentPR)(config); - compliant && (compliant = result.compliant); - yield (0, github_1.updateLabels)(yield determineLabels(result.messages, config)); - } - if (core.getBooleanInput("validate-pull-request-title-bump")) { - const ok = yield (0, validate_1.validatePrTitleBump)(config); - compliant && (compliant = ok); - // Validating the PR title bump level implies validating the title itself - } - else if (core.getBooleanInput("validate-pull-request")) { - const ok = (yield (0, validate_1.validatePrTitle)(config)) !== undefined; - compliant && (compliant = ok); - } - core.info(""); // add vertical whitespace - if (compliant) { - core.info("✅ The pull request passed all configured checks"); - } + if (core.getBooleanInput("validate-pull-request-title-bump")) { + const ok = await (0, validate_1.validatePrTitleBump)(config); + compliant && (compliant = ok); + // Validating the PR title bump level implies validating the title itself } - catch (ex) { - core.setFailed(ex.message); + else if (core.getBooleanInput("validate-pull-request")) { + const ok = (await (0, validate_1.validatePrTitle)(config)) !== undefined; + compliant && (compliant = ok); } - }); + core.info(""); // add vertical whitespace + if (compliant) { + core.info("✅ The pull request passed all configured checks"); + } + } + catch (ex) { + core.setFailed(ex.message); + } } -run(); -exports.exportedForTesting = { - run, -}; +exports.run = run; /***/ }), @@ -33762,15 +33752,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.bumpSdkVer = exports.bumpSemVer = exports.publishBump = exports.printNonCompliance = exports.bumpDraftRelease = exports.getVersionBumpTypeAndMessages = exports.getVersionBumpType = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -33835,9 +33816,9 @@ function processCommitsForBump(commits, config) { // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = JSON.parse(JSON.stringify(config)); - configCopy.rules["C014"].enabled = false; // SubjectExceedsLineLengthLimit - configCopy.rules["C019"].enabled = false; // SubjectContainsIssueReference + const configCopy = Object.create(config); + configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference return (0, validate_1.processCommits)(commits, configCopy); } /** @@ -33879,57 +33860,55 @@ exports.getVersionBumpType = getVersionBumpType; - state of "initial development"; if no version is found, err on the safe side and declare "initial development" (if configured as such) */ -function getVersionBumpTypeAndMessages(targetSha, config) { - return __awaiter(this, void 0, void 0, function* () { - core.debug(`Fetching last ${PAGE_SIZE} tags from ${targetSha}..`); - const tags = yield (0, github_1.getLatestTags)(PAGE_SIZE); - core.debug("Fetch complete"); - const tagMatcher = (commitMessage, commitSha) => { - // Try and match this commit's hash to one of the tags in `tags` - for (const tag of tags) { - let semVer = null; - core.debug(`Considering tag ${tag.name} (${tag.commitSha}) on ${commitSha}`); - semVer = getSemVerIfMatches(config.versionPrefix, tag.name, tag.commitSha, commitSha); - if (semVer) { - // We've found a tag that matches to this commit. Now, we need to - // make sure that we return the _highest_ version tag_ associated with - // this commit - core.debug(`Matching tag found (${tag.name}), checking other tags for commit ${commitSha}..`); - const matchTags = tags.filter(t => t.commitSha === commitSha); - if (matchTags.length > 1) { - core.debug(`${matchTags.length} other tags found`); - matchTags.sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); - semVer = null; - while (semVer === null && matchTags.length !== 0) { - const t = matchTags.pop(); - if (!t) - break; - semVer = getSemVerIfMatches(config.versionPrefix, t.name, t.commitSha, commitSha); - } - } - else { - core.debug(`No other tags found`); - // Just the one tag; carry on. +async function getVersionBumpTypeAndMessages(targetSha, config) { + core.debug(`Fetching last ${PAGE_SIZE} tags from ${targetSha}..`); + const tags = await (0, github_1.getLatestTags)(PAGE_SIZE); + core.debug("Fetch complete"); + const tagMatcher = (commitSha) => { + // Try and match this commit's hash to one of the tags in `tags` + for (const tag of tags) { + let semVer = null; + core.debug(`Considering tag ${tag.name} (${tag.commitSha}) on ${commitSha}`); + semVer = getSemVerIfMatches(config.versionPrefix, tag.name, tag.commitSha, commitSha); + if (semVer) { + // We've found a tag that matches to this commit. Now, we need to + // make sure that we return the _highest_ version tag_ associated with + // this commit + core.debug(`Matching tag found (${tag.name}), checking other tags for commit ${commitSha}..`); + const matchTags = tags.filter(t => t.commitSha === commitSha); + if (matchTags.length > 1) { + core.debug(`${matchTags.length} other tags found`); + matchTags.sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); + semVer = null; + while (semVer === null && matchTags.length !== 0) { + const t = matchTags.pop(); + if (!t) + break; + semVer = getSemVerIfMatches(config.versionPrefix, t.name, t.commitSha, commitSha); } - return semVer; } + else { + core.debug(`No other tags found`); + // Just the one tag; carry on. + } + return semVer; } - core.debug(`Commit ${commitSha.slice(0, 6)} is not associated with a tag`); - return null; - }; - const [version, commitList] = yield (0, github_1.matchTagsToCommits)(targetSha, tagMatcher); - const results = processCommitsForBump(commitList, config); - const convCommits = results - .map(r => r.message) - .filter((r) => r !== undefined); - return { - foundVersion: version, - requiredBump: getVersionBumpType(convCommits), - processedCommits: results, - initialDevelopment: config.initialDevelopment && - (!version || (version && version.major === 0)), - }; - }); + } + core.debug(`Commit ${commitSha.slice(0, 6)} is not associated with a tag`); + return null; + }; + const [version, commitList] = await (0, github_1.matchTagsToCommits)(targetSha, tagMatcher); + const results = processCommitsForBump(commitList, config); + const convCommits = results + .map(r => r.message) + .filter((r) => r !== undefined); + return { + foundVersion: version, + requiredBump: getVersionBumpType(convCommits), + processedCommits: results, + initialDevelopment: config.initialDevelopment && + (!version || (version && version.major === 0)), + }; } exports.getVersionBumpTypeAndMessages = getVersionBumpTypeAndMessages; /** @@ -33944,57 +33923,51 @@ exports.getVersionBumpTypeAndMessages = getVersionBumpTypeAndMessages; * Returns the new prerelease version name if update was successful, * `undefined` otherwise. */ -function tryUpdateDraftRelease(cv, changelog, sha) { - return __awaiter(this, void 0, void 0, function* () { - const latestDraftRelease = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, - draftOnly: true, - fullReleasesOnly: false, - }); - if (!latestDraftRelease) - return; - const currentDraftVersion = semver_1.SemVer.fromString(latestDraftRelease.name); - if (!currentDraftVersion) { - core.info(`Couldn't parse ${latestDraftRelease.name} as SemVer`); - return; - } - const npv = currentDraftVersion.nextPrerelease(); - if (!npv) - return; - npv.build = shortSha(sha); - const updateSuccess = yield (0, github_1.updateDraftRelease)(latestDraftRelease.id, npv.toString(), npv.toString(), sha, changelog); - if (!updateSuccess) { - core.info(`Error renaming existing draft release.`); - return; - } - return npv.toString(); +async function tryUpdateDraftRelease(cv, changelog, sha) { + const latestDraftRelease = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: true, + fullReleasesOnly: false, }); + if (!latestDraftRelease) + return; + const currentDraftVersion = semver_1.SemVer.fromString(latestDraftRelease.name); + if (!currentDraftVersion) { + core.info(`Couldn't parse ${latestDraftRelease.name} as SemVer`); + return; + } + const npv = currentDraftVersion.nextPrerelease(); + if (!npv) + return; + npv.build = shortSha(sha); + const updateSuccess = await (0, github_1.updateDraftRelease)(latestDraftRelease.id, npv.toString(), npv.toString(), sha, changelog); + if (!updateSuccess) { + core.info(`Error renaming existing draft release.`); + return; + } + return npv.toString(); } -function newDraftRelease(currentVersion, changelog, sha, prefix) { - return __awaiter(this, void 0, void 0, function* () { - // Either update went wrong or there was nothing to update - const nextPrereleaseVersion = currentVersion.nextPatch(); - nextPrereleaseVersion.build = currentVersion.build; - if (prefix === "dev") { - nextPrereleaseVersion.prerelease = `${prefix}001.${shortSha(sha)}`; - } - else { - nextPrereleaseVersion.prerelease = `${prefix}001`; - } - yield (0, github_1.createRelease)(nextPrereleaseVersion.toString(), sha, changelog, true, false); - return nextPrereleaseVersion.toString(); - }); +async function newDraftRelease(currentVersion, changelog, sha, prefix) { + // Either update went wrong or there was nothing to update + const nextPrereleaseVersion = currentVersion.nextPatch(); + nextPrereleaseVersion.build = currentVersion.build; + if (prefix === "dev") { + nextPrereleaseVersion.prerelease = `${prefix}001.${shortSha(sha)}`; + } + else { + nextPrereleaseVersion.prerelease = `${prefix}001`; + } + await (0, github_1.createRelease)(nextPrereleaseVersion.toString(), sha, changelog, true, false); + return nextPrereleaseVersion.toString(); } -function bumpDraftRelease(bumpInfo, changelog, sha, preRelPrefix) { +async function bumpDraftRelease(bumpInfo, changelog, sha, preRelPrefix) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const cv = bumpInfo.foundVersion; - if (!cv) - throw Error("Found version is falsy"); // should never happen - const result = (_a = (yield tryUpdateDraftRelease(cv, changelog, sha))) !== null && _a !== void 0 ? _a : (yield newDraftRelease(cv, changelog, sha, preRelPrefix)); - core.info(`ℹ️ Next prerelease: ${result}`); - return result; - }); + const cv = bumpInfo.foundVersion; + if (!cv) + throw Error("Found version is falsy"); // should never happen + const result = (_a = (await tryUpdateDraftRelease(cv, changelog, sha))) !== null && _a !== void 0 ? _a : (await newDraftRelease(cv, changelog, sha, preRelPrefix)); + core.info(`ℹ️ Next prerelease: ${result}`); + return result; } exports.bumpDraftRelease = bumpDraftRelease; /** @@ -34027,146 +34000,142 @@ function printNonCompliance(commits) { } } exports.printNonCompliance = printNonCompliance; -function publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, updateDraftId) { - return __awaiter(this, void 0, void 0, function* () { - const nv = nextVersion.toString(); - core.info(`ℹ️ Next version: ${nv}`); - core.setOutput("next-version", nv); - core.endGroup(); - if (releaseMode !== "none") { - if (!isBranchAllowedToPublish) { - return false; - } - if ((0, github_1.isPullRequestEvent)()) { - core.startGroup(`ℹ️ Not creating ${releaseMode} on a pull request event.`); - core.info("We cannot create a release or tag in a pull request context, due to " + - "potential parallelism (i.e. races) in pull request builds."); - return false; +async function publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, updateDraftId) { + const nv = nextVersion.toString(); + core.info(`ℹ️ Next version: ${nv}`); + core.setOutput("next-version", nv); + core.endGroup(); + if (releaseMode !== "none") { + if (!isBranchAllowedToPublish) { + return false; + } + if ((0, github_1.isPullRequestEvent)()) { + core.startGroup(`ℹ️ Not creating ${releaseMode} on a pull request event.`); + core.info("We cannot create a release or tag in a pull request context, due to " + + "potential parallelism (i.e. races) in pull request builds."); + return false; + } + core.startGroup(`ℹ️ Creating ${releaseMode} ${nv}..`); + try { + if (releaseMode === "tag") { + await (0, github_1.createTag)(nv, headSha); } - core.startGroup(`ℹ️ Creating ${releaseMode} ${nv}..`); - try { - if (releaseMode === "tag") { - yield (0, github_1.createTag)(nv, headSha); - } - else { - // If version is a prerelease, but not an RC, create a draft release - // If version is an RC, create a GitHub "pre-release" - const isRc = nextVersion.prerelease.startsWith(RC_PREFIX); - const isDev = nextVersion.prerelease !== "" && !isRc; - let updated = false; - if (updateDraftId) { - updated = yield (0, github_1.updateDraftRelease)(updateDraftId, nv, nv, headSha, changelog, isDev, // draft - isRc // prerelease - ); - if (!updated) { - core.info(`Error renaming existing draft release, ` + - `creating new draft release.`); - } - } + else { + // If version is a prerelease, but not an RC, create a draft release + // If version is an RC, create a GitHub "pre-release" + const isRc = nextVersion.prerelease.startsWith(RC_PREFIX); + const isDev = nextVersion.prerelease !== "" && !isRc; + let updated = false; + if (updateDraftId) { + updated = await (0, github_1.updateDraftRelease)(updateDraftId, nv, nv, headSha, changelog, isDev, // draft + isRc // prerelease + ); if (!updated) { - yield (0, github_1.createRelease)(nv, headSha, changelog, isDev, isRc); + core.info(`Error renaming existing draft release, ` + + `creating new draft release.`); } } - } - catch (ex) { - // The most likely failure is a preexisting tag, in which case - // a RequestError with statuscode 422 will be thrown - const commit = yield (0, github_1.getShaForTag)(`refs/tags/${nv}`); - if (ex instanceof request_error_1.RequestError && ex.status === 422 && commit) { - core.setFailed(`Unable to create ${releaseMode}; the tag "${nv}" already exists in the repository, ` + - `it currently points to ${commit}.\n` + - "You can find the branch(es) associated with the tag with:\n" + - ` git fetch -t; git branch --contains ${nv}`); - } - else if (ex instanceof request_error_1.RequestError) { - core.setFailed(`Unable to create ${releaseMode} with the name "${nv}" due to ` + - `HTTP request error (status ${ex.status}):\n${ex.message}`); - } - else if (ex instanceof Error) { - core.setFailed(`Unable to create ${releaseMode} with the name "${nv}":\n${ex.message}`); - } - else { - core.setFailed(`Unknown error during ${releaseMode} creation`); - throw ex; + if (!updated) { + await (0, github_1.createRelease)(nv, headSha, changelog, isDev, isRc); } - core.endGroup(); - return false; } - core.info("Succeeded"); } - else { - core.startGroup(`ℹ️ Not creating tag or release for ${nv}..`); - core.info("To create a lightweight Git tag or GitHub release when the version is bumped, run this action with:\n" + - ' - "create-release" set to "true" to create a GitHub release, or\n' + - ' - "create-tag" set to "true" for a lightweight Git tag.\n' + - "Note that setting both options is not needed, since a GitHub release implicitly creates a Git tag."); + catch (ex) { + // The most likely failure is a preexisting tag, in which case + // a RequestError with statuscode 422 will be thrown + const commit = await (0, github_1.getShaForTag)(`refs/tags/${nv}`); + if (ex instanceof request_error_1.RequestError && ex.status === 422 && commit) { + core.setFailed(`Unable to create ${releaseMode}; the tag "${nv}" already exists in the repository, ` + + `it currently points to ${commit}.\n` + + "You can find the branch(es) associated with the tag with:\n" + + ` git fetch -t; git branch --contains ${nv}`); + } + else if (ex instanceof request_error_1.RequestError) { + core.setFailed(`Unable to create ${releaseMode} with the name "${nv}" due to ` + + `HTTP request error (status ${ex.status}):\n${ex.message}`); + } + else if (ex instanceof Error) { + core.setFailed(`Unable to create ${releaseMode} with the name "${nv}":\n${ex.message}`); + } + else { + core.setFailed(`Unknown error during ${releaseMode} creation`); + throw ex; + } + core.endGroup(); return false; } - return true; - }); + core.info("Succeeded"); + } + else { + core.startGroup(`ℹ️ Not creating tag or release for ${nv}..`); + core.info("To create a lightweight Git tag or GitHub release when the version is bumped, run this action with:\n" + + ' - "create-release" set to "true" to create a GitHub release, or\n' + + ' - "create-tag" set to "true" for a lightweight Git tag.\n' + + "Note that setting both options is not needed, since a GitHub release implicitly creates a Git tag."); + return false; + } + return true; } exports.publishBump = publishBump; -function bumpSemVer(config, bumpInfo, releaseMode, branchName, headSha, isBranchAllowedToPublish, createChangelog) { +async function bumpSemVer(config, bumpInfo, releaseMode, branchName, headSha, isBranchAllowedToPublish, createChangelog) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const compliantCommits = bumpInfo.processedCommits - .filter(c => c.message !== undefined) - .map(c => ({ - msg: c.message, - sha: c.input.sha.slice(0, 8), - })); - for (const { msg, sha } of compliantCommits) { - const bumpString = msg.bump === 0 ? "No" : semver_1.SemVerType[msg.bump]; - core.info(`- ${bumpString} bump for commit (${sha}): ${msg.subject}`); - } - // Reject MAJOR and MINOR version bumps if we're on a release branch - // (Purposefully do this check _after_ listing the processed commits.) - if (branchName.match(config.releaseBranches) && - [semver_1.SemVerType.MAJOR, semver_1.SemVerType.MINOR].includes(bumpInfo.requiredBump)) { - core.setFailed(`A ${semver_1.SemVerType[bumpInfo.requiredBump]} bump is requested, but ` + - `we can only create PATCH bumps on a release branch.`); - return false; + const compliantCommits = bumpInfo.processedCommits + .filter(c => c.message !== undefined) + .map(c => ({ + msg: c.message, + sha: c.input.sha.slice(0, 8), + })); + for (const { msg, sha } of compliantCommits) { + const bumpString = msg.bump === 0 ? "No" : semver_1.SemVerType[msg.bump]; + core.info(`- ${bumpString} bump for commit (${sha}): ${msg.subject}`); + } + // Reject MAJOR and MINOR version bumps if we're on a release branch + // (Purposefully do this check _after_ listing the processed commits.) + if (branchName.match(config.releaseBranches) && + [semver_1.SemVerType.MAJOR, semver_1.SemVerType.MINOR].includes(bumpInfo.requiredBump)) { + core.setFailed(`A ${semver_1.SemVerType[bumpInfo.requiredBump]} bump is requested, but ` + + `we can only create PATCH bumps on a release branch.`); + return false; + } + const nextVersion = (_a = bumpInfo.foundVersion) === null || _a === void 0 ? void 0 : _a.bump(bumpInfo.requiredBump, config.initialDevelopment); + let changelog = ""; + if (createChangelog) + changelog = await (0, changelog_1.generateChangelog)(bumpInfo); + let bumped = false; + if (nextVersion) { + const buildMetadata = core.getInput("build-metadata"); + if (buildMetadata) { + nextVersion.build = buildMetadata; } - const nextVersion = (_a = bumpInfo.foundVersion) === null || _a === void 0 ? void 0 : _a.bump(bumpInfo.requiredBump, config.initialDevelopment); - let changelog = ""; - if (createChangelog) - changelog = yield (0, changelog_1.generateChangelog)(bumpInfo); - let bumped = false; - if (nextVersion) { - const buildMetadata = core.getInput("build-metadata"); - if (buildMetadata) { - nextVersion.build = buildMetadata; - } - bumped = yield publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish); + bumped = await publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish); + } + else { + core.info("ℹ️ No bump necessary"); + core.setOutput("next-version", ""); + } + core.endGroup(); + if (!bumped && config.prereleasePrefix !== undefined) { + // When configured to create GitHub releases, and the `bump-prereleases` config item + // evaluates to `true`. + if (isBranchAllowedToPublish && + !(0, github_1.isPullRequestEvent)() && + releaseMode === "release") { + // Create/rename draft release + const ver = await bumpDraftRelease(bumpInfo, changelog, headSha, config.prereleasePrefix); + core.info(`ℹ️ Created draft prerelease version ${ver}`); } else { - core.info("ℹ️ No bump necessary"); - core.setOutput("next-version", ""); + const reason = isBranchAllowedToPublish !== true + ? `the current branch is not allowed to publish` + : (0, github_1.isPullRequestEvent)() + ? "we cannot publish from a pull request event" + : releaseMode !== "release" + ? `we can only do so when the 'create-release' input is provided to be 'true'` + : "we didn't think of writing an error message here"; + core.info(`ℹ️ While configured to bump prereleases, ${reason}.`); } - core.endGroup(); - if (!bumped && config.prereleasePrefix !== undefined) { - // When configured to create GitHub releases, and the `bump-prereleases` config item - // evaluates to `true`. - if (isBranchAllowedToPublish && - !(0, github_1.isPullRequestEvent)() && - releaseMode === "release") { - // Create/rename draft release - const ver = yield bumpDraftRelease(bumpInfo, changelog, headSha, config.prereleasePrefix); - core.info(`ℹ️ Created draft prerelease version ${ver}`); - } - else { - const reason = isBranchAllowedToPublish !== true - ? `the current branch is not allowed to publish` - : (0, github_1.isPullRequestEvent)() - ? "we cannot publish from a pull request event" - : releaseMode !== "release" - ? `we can only do so when the 'create-release' input is provided to be 'true'` - : "we didn't think of writing an error message here"; - core.info(`ℹ️ While configured to bump prereleases, ${reason}.`); - } - } - return bumped; - }); + } + return bumped; } exports.bumpSemVer = bumpSemVer; function getNextSdkVer(currentVersion, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, devPrereleaseText, headSha, isInitialDevelopment) { @@ -34338,115 +34307,113 @@ function getNextSdkVer(currentVersion, sdkVerBumpType, isReleaseBranch, headMatc /** * Bump and release/tag SDK versions */ -function bumpSdkVer(config, bumpInfo, releaseMode, sdkVerBumpType, headSha, branchName, isBranchAllowedToPublish, createChangelog) { +async function bumpSdkVer(config, bumpInfo, releaseMode, sdkVerBumpType, headSha, branchName, isBranchAllowedToPublish, createChangelog) { var _a, _b, _c, _d, _e, _f; - return __awaiter(this, void 0, void 0, function* () { - const isReleaseBranch = branchName.match(config.releaseBranches); - const hasBreakingChange = bumpInfo.processedCommits.some(c => { var _a; return (_a = c.message) === null || _a === void 0 ? void 0 : _a.breakingChange; }); - if (!bumpInfo.foundVersion) - return false; // should never happen - // SdkVer requires a prerelease, so apply the default if not set - config.prereleasePrefix = (_a = config.prereleasePrefix) !== null && _a !== void 0 ? _a : "dev"; - let cv = semver_1.SemVer.copy(bumpInfo.foundVersion); - // Get the latest draft release matching our current version's prefix. - // Don't look at the draft version on a release branch; the current version - // should always reflect the version to be bumped (as no dev releases are - // allowed on a release branch) - const latestDraft = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, - draftOnly: true, - fullReleasesOnly: false, - }); - const latestRelease = yield (0, github_1.getRelease)({ - prefixToMatch: cv.prefix, + const isReleaseBranch = branchName.match(config.releaseBranches) !== null; + const hasBreakingChange = bumpInfo.processedCommits.some(c => { var _a; return (_a = c.message) === null || _a === void 0 ? void 0 : _a.breakingChange; }); + if (!bumpInfo.foundVersion) + return false; // should never happen + // SdkVer requires a prerelease, so apply the default if not set + config.prereleasePrefix = (_a = config.prereleasePrefix) !== null && _a !== void 0 ? _a : "dev"; + let cv = semver_1.SemVer.copy(bumpInfo.foundVersion); + // Get the latest draft release matching our current version's prefix. + // Don't look at the draft version on a release branch; the current version + // should always reflect the version to be bumped (as no dev releases are + // allowed on a release branch) + const latestDraft = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: true, + fullReleasesOnly: false, + }); + const latestRelease = await (0, github_1.getRelease)({ + prefixToMatch: cv.prefix, + draftOnly: false, + fullReleasesOnly: true, + }); + core.info(`Current version: ${cv.toString()}, latest GitHub release draft: ${(_b = latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.name) !== null && _b !== void 0 ? _b : "NONE"}, latest GitHub release: ${(_c = latestRelease === null || latestRelease === void 0 ? void 0 : latestRelease.name) !== null && _c !== void 0 ? _c : "NONE"}`); + if (!isReleaseBranch && latestDraft) { + // If we're not on a release branch and a draft version exists that is + // newer than the latest tag, we continue with that + const draftVersion = semver_1.SemVer.fromString(latestDraft.name); + if (draftVersion && cv.lessThan(draftVersion)) { + cv = draftVersion; + } + } + // TODO: This is wasteful, as this info has already been available before + const headMatchesTag = await (0, github_1.currentHeadMatchesTag)(cv.toString()); + const nextVersion = getNextSdkVer(cv, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, (_d = config.prereleasePrefix) !== null && _d !== void 0 ? _d : "dev", headSha, config.initialDevelopment); + let bumped = false; + if (nextVersion) { + // Since we want the changelog since the last _full_ release, we + // can only rely on the `bumpInfo` if the "current version" is a + // full release. In other cases, we need to gather some information + // to generate the proper changelog. + const previousRelease = await (0, github_1.getRelease)({ + prefixToMatch: nextVersion.prefix, draftOnly: false, fullReleasesOnly: true, + constraint: { + major: nextVersion.major, + minor: nextVersion.minor, + }, }); - core.info(`Current version: ${cv.toString()}, latest GitHub release draft: ${(_b = latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.name) !== null && _b !== void 0 ? _b : "NONE"}, latest GitHub release: ${(_c = latestRelease === null || latestRelease === void 0 ? void 0 : latestRelease.name) !== null && _c !== void 0 ? _c : "NONE"}`); - if (!isReleaseBranch && latestDraft) { - // If we're not on a release branch and a draft version exists that is - // newer than the latest tag, we continue with that - const draftVersion = semver_1.SemVer.fromString(latestDraft.name); - if (draftVersion && cv.lessThan(draftVersion)) { - cv = draftVersion; + core.info(`The full release preceding the current one is ${(_e = previousRelease === null || previousRelease === void 0 ? void 0 : previousRelease.name) !== null && _e !== void 0 ? _e : "undefined"}`); + let changelog = ""; + if (createChangelog) { + if (previousRelease && cv.prerelease) { + const toVersion = + // Since "dev" releases on non-release-branches result in a draft + // release, we'll need to use the commit sha. + sdkVerBumpType === "dev" && !isReleaseBranch + ? shortSha(headSha) + : nextVersion.toString(); + changelog = await (0, changelog_1.generateChangelogForCommits)(previousRelease.name, toVersion, await collectChangelogCommits(previousRelease.name, config)); + } + else { + changelog = await (0, changelog_1.generateChangelog)(bumpInfo); } } - // TODO: This is wasteful, as this info has already been available before - const headMatchesTag = yield (0, github_1.currentHeadMatchesTag)(cv.toString()); - const nextVersion = getNextSdkVer(cv, sdkVerBumpType, isReleaseBranch, headMatchesTag, hasBreakingChange, (_d = config.prereleasePrefix) !== null && _d !== void 0 ? _d : "dev", headSha, config.initialDevelopment); - let bumped = false; - if (nextVersion) { - // Since we want the changelog since the last _full_ release, we - // can only rely on the `bumpInfo` if the "current version" is a - // full release. In other cases, we need to gather some information - // to generate the proper changelog. - const previousRelease = yield (0, github_1.getRelease)({ - prefixToMatch: nextVersion.prefix, - draftOnly: false, - fullReleasesOnly: true, - constraint: { - major: nextVersion.major, - minor: nextVersion.minor, - }, - }); - core.info(`The full release preceding the current one is ${(_e = previousRelease === null || previousRelease === void 0 ? void 0 : previousRelease.name) !== null && _e !== void 0 ? _e : "undefined"}`); - let changelog = ""; - if (createChangelog) { - if (previousRelease && cv.prerelease) { - const toVersion = - // Since "dev" releases on non-release-branches result in a draft - // release, we'll need to use the commit sha. - sdkVerBumpType === "dev" && !isReleaseBranch - ? shortSha(headSha) - : nextVersion.toString(); - changelog = yield (0, changelog_1.generateChangelogForCommits)(previousRelease.name, toVersion, yield collectChangelogCommits(previousRelease.name, config)); + bumped = await publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, + // Re-use the latest draft release only when not running on a release branch, + // otherwise we might randomly reset a `dev-N` number chain. + !isReleaseBranch ? latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.id : undefined); + } + if (!bumped) { + core.info("ℹ️ No bump was performed"); + } + else { + // Create a release branch for releases and RC's if we're configured to do so + // and are currently not running on a release branch. + if (config.sdkverCreateReleaseBranches !== undefined && + !isReleaseBranch && + sdkVerBumpType !== "dev") { + const releaseBranchName = `${config.sdkverCreateReleaseBranches}${nextVersion.major}.${nextVersion.minor}`; + core.info(`Creating release branch ${releaseBranchName}..`); + try { + await (0, github_1.createBranch)(`refs/heads/${releaseBranchName}`, headSha); + } + catch (ex) { + if (ex instanceof request_error_1.RequestError && ex.status === 422) { + core.warning(`The branch '${releaseBranchName}' already exists` + + `${(0, github_1.getRunNumber)() !== 1 ? " (NOTE: this is a re-run)." : "."}`); } - else { - changelog = yield (0, changelog_1.generateChangelog)(bumpInfo); + else if (ex instanceof request_error_1.RequestError) { + core.warning(`Unable to create release branch '${releaseBranchName}' due to ` + + `HTTP request error (status ${ex.status}):\n${ex.message}`); } - } - bumped = yield publishBump(nextVersion, releaseMode, headSha, changelog, isBranchAllowedToPublish, - // Re-use the latest draft release only when not running on a release branch, - // otherwise we might randomly reset a `dev-N` number chain. - !isReleaseBranch ? latestDraft === null || latestDraft === void 0 ? void 0 : latestDraft.id : undefined); - } - if (!bumped) { - core.info("ℹ️ No bump was performed"); - } - else { - // Create a release branch for releases and RC's if we're configured to do so - // and are currently not running on a release branch. - if (config.sdkverCreateReleaseBranches !== undefined && - !isReleaseBranch && - sdkVerBumpType !== "dev") { - const releaseBranchName = `${config.sdkverCreateReleaseBranches}${nextVersion.major}.${nextVersion.minor}`; - core.info(`Creating release branch ${releaseBranchName}..`); - try { - yield (0, github_1.createBranch)(`refs/heads/${releaseBranchName}`, headSha); + else if (ex instanceof Error) { + core.warning(`Unable to create release branch '${releaseBranchName}':\n${ex.message}`); } - catch (ex) { - if (ex instanceof request_error_1.RequestError && ex.status === 422) { - core.warning(`The branch '${releaseBranchName}' already exists` + - `${(0, github_1.getRunNumber)() !== 1 ? " (NOTE: this is a re-run)." : "."}`); - } - else if (ex instanceof request_error_1.RequestError) { - core.warning(`Unable to create release branch '${releaseBranchName}' due to ` + - `HTTP request error (status ${ex.status}):\n${ex.message}`); - } - else if (ex instanceof Error) { - core.warning(`Unable to create release branch '${releaseBranchName}':\n${ex.message}`); - } - else { - core.warning(`Unknown error during ${releaseMode} creation`); - throw ex; - } + else { + core.warning(`Unknown error during ${releaseMode} creation`); + throw ex; } } } - core.setOutput("next-version", (_f = nextVersion === null || nextVersion === void 0 ? void 0 : nextVersion.toString()) !== null && _f !== void 0 ? _f : ""); - core.endGroup(); - return bumped; - }); + } + core.setOutput("next-version", (_f = nextVersion === null || nextVersion === void 0 ? void 0 : nextVersion.toString()) !== null && _f !== void 0 ? _f : ""); + core.endGroup(); + return bumped; } exports.bumpSdkVer = bumpSdkVer; /** @@ -34458,19 +34425,17 @@ exports.bumpSdkVer = bumpSdkVer; * - the name of the last full release reachable from our current version * - the list of valid Conventional Commit objects since that release */ -function collectChangelogCommits(previousRelease, config) { - return __awaiter(this, void 0, void 0, function* () { - core.startGroup(`📜 Gathering changelog information`); - const commits = yield (0, github_1.getCommitsBetweenRefs)(previousRelease); - core.info(`Processing commit list (since ${previousRelease}) ` + - `for changelog generation:\n-> ` + - `${commits.map(c => c.message.split("\n")[0]).join("\n-> ")}`); - const processedCommits = processCommitsForBump(commits, config); - core.endGroup(); - return processedCommits - .map(c => c.message) - .filter(c => c); - }); +async function collectChangelogCommits(previousRelease, config) { + core.startGroup(`📜 Gathering changelog information`); + const commits = await (0, github_1.getCommitsBetweenRefs)(previousRelease); + core.info(`Processing commit list (since ${previousRelease}) ` + + `for changelog generation:\n-> ` + + `${commits.map(c => c.message.split("\n")[0]).join("\n-> ")}`); + const processedCommits = processCommitsForBump(commits, config); + core.endGroup(); + return processedCommits + .map(c => c.message) + .filter(c => c); } @@ -34519,15 +34484,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.generateChangelog = exports.generateChangelogForCommits = exports.getChangelogConfiguration = void 0; const github_1 = __nccwpck_require__(5438); @@ -34570,20 +34526,18 @@ const DEFAULT_CONFIG = { * Generates a Pull Request suffix `(#123)` in case this is not yet present * in the commit description. */ -function getPullRequestSuffix(commit) { - return __awaiter(this, void 0, void 0, function* () { - if (commit.hexsha && !commit.description.match(/\s\(#[0-9]+\)$/)) { - const pull_requests = yield (0, github_2.getAssociatedPullRequests)(commit.hexsha); - const pr_references = []; - for (const pull_request of pull_requests) { - pr_references.push(`#${pull_request.number}`); - } - if (pr_references.length > 0) { - return ` (${pr_references.join(", ")})`; - } +async function getPullRequestSuffix(commit) { + if (commit.hexsha && !commit.description.match(/\s\(#[0-9]+\)$/)) { + const pull_requests = await (0, github_2.getAssociatedPullRequests)(commit.hexsha); + const pr_references = []; + for (const pull_request of pull_requests) { + pr_references.push(`#${pull_request.number}`); } - return ""; - }); + if (pr_references.length > 0) { + return ` (${pr_references.join(", ")})`; + } + } + return ""; } /** * Generates an Issue suffix `(TEST-123, TEST-456)` based on the issue @@ -34607,37 +34561,33 @@ function getIssueReferenceSuffix(commit) { * Creates an entry in the Changelog based on the provided * Conventional Commit message. */ -function generateChangelogEntry(commit) { - return __awaiter(this, void 0, void 0, function* () { - const { owner, repo } = github_1.context.repo; - let changelogEntry = `${commit.description - .charAt(0) - .toUpperCase()}${commit.description.slice(1)}`; - changelogEntry += yield getPullRequestSuffix(commit); - changelogEntry += getIssueReferenceSuffix(commit); - if (commit.hexsha) { - const sha_link = `[${commit.hexsha.slice(0, 6)}](https://github.com/${owner}/${repo}/commit/${commit.hexsha})`; - changelogEntry += ` [${sha_link}]`; - } - return changelogEntry; - }); +async function generateChangelogEntry(commit) { + const { owner, repo } = github_1.context.repo; + let changelogEntry = `${commit.description + .charAt(0) + .toUpperCase()}${commit.description.slice(1)}`; + changelogEntry += await getPullRequestSuffix(commit); + changelogEntry += getIssueReferenceSuffix(commit); + if (commit.hexsha) { + const sha_link = `[${commit.hexsha.slice(0, 6)}](https://github.com/${owner}/${repo}/commit/${commit.hexsha})`; + changelogEntry += ` [${sha_link}]`; + } + return changelogEntry; } /** * Returns the Changelog configuration; * - The contents of the .github/release.y[a]ml file * - Otherwise, the internal default configuration */ -function getChangelogConfiguration() { - return __awaiter(this, void 0, void 0, function* () { - const githubReleaseConfig = yield (0, github_2.getReleaseConfiguration)(); - if (githubReleaseConfig.length > 0) { - const data = yaml.parse(githubReleaseConfig); - if (data["changelog"] !== undefined) { - return data; - } +async function getChangelogConfiguration() { + const githubReleaseConfig = await (0, github_2.getReleaseConfiguration)(); + if (githubReleaseConfig.length > 0) { + const data = yaml.parse(githubReleaseConfig); + if (data["changelog"] !== undefined) { + return data; } - return JSON.parse(JSON.stringify(DEFAULT_CONFIG)); - }); + } + return JSON.parse(JSON.stringify(DEFAULT_CONFIG)); } exports.getChangelogConfiguration = getChangelogConfiguration; /** @@ -34650,116 +34600,112 @@ exports.getChangelogConfiguration = getChangelogConfiguration; * `endVersion` can be an empty string, in which case the current HEAD sha * will be used. */ -function generateChangelogForCommits(startVersion, endVersion, commitList) { +async function generateChangelogForCommits(startVersion, endVersion, commitList) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; - return __awaiter(this, void 0, void 0, function* () { - if (startVersion === "") { - return ""; + if (startVersion === "") { + return ""; + } + const config = await getChangelogConfiguration(); + const changelog = new Map(); + for (const commit of commitList) { + if (!commit) + continue; + const bumpLabel = Label.create("bump", semver_1.SemVerType[commit.bump]); + const typeLabel = Label.create("type", commit.type); + const scopeLabel = Label.create("scope", ((_a = commit.scope) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "*"); + // Adds the following items as "virtual" labels for each commit: + // * The version bump (`bump:`) + // * The conventional commit type (`type:`) + // * The conventional commit scope (`scope:`) + let labels = [bumpLabel, typeLabel, scopeLabel]; + // We will reuse the labels and author associated with a Pull Request + // (with the exception of `bump:` and `scope:`) for all + // commits associated with the PR. + if (commit.hexsha) { + const pullRequests = await (0, github_2.getAssociatedPullRequests)(commit.hexsha); + if (pullRequests.length > 0) { + const pullRequest = pullRequests[0]; + // Append the labels of the associated Pull Request + // NOTE: we ignore the version bump and scope label on the PR as this is + // and instead rely on version bump label associated with this + // commit. + labels = labels.concat(pullRequest.labels + .filter(label => !Label.isCategory(label.name, "bump") && + !Label.isCategory(label.name, "scope")) + .map(label => label.name)); + // Check if the author of the Pull Request is part of the exclude list + if (pullRequest.user && + ((_c = (_b = config.changelog.exclude) === null || _b === void 0 ? void 0 : _b.authors) === null || _c === void 0 ? void 0 : _c.includes(pullRequest.user.login))) { + continue; + } + } + } + // Check if any of the labels is part of the global exclusion list + if (labels.some(label => { var _a, _b; return (_b = (_a = config.changelog.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { + continue; } - const config = yield getChangelogConfiguration(); - const changelog = new Map(); - for (const commit of commitList) { - if (!commit) + // Either group commits per Conventional Commit scope, or group them all + // together (*) + const scope = config.changelog.group === "scope" + ? ((_d = commit === null || commit === void 0 ? void 0 : commit.scope) === null || _d === void 0 ? void 0 : _d.toLowerCase()) || "*" + : "*"; + changelog.set(scope, (_e = changelog.get(scope)) !== null && _e !== void 0 ? _e : new Map()); + for (const category of config.changelog.categories) { + // Apply all exclusion patterns from Pull Request metadata on Category + if (labels.some(label => { var _a, _b; return (_b = (_a = category.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { continue; - const bumpLabel = Label.create("bump", semver_1.SemVerType[commit.bump]); - const typeLabel = Label.create("type", commit.type); - const scopeLabel = Label.create("scope", ((_a = commit.scope) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "*"); - // Adds the following items as "virtual" labels for each commit: - // * The version bump (`bump:`) - // * The conventional commit type (`type:`) - // * The conventional commit scope (`scope:`) - let labels = [bumpLabel, typeLabel, scopeLabel]; - // We will reuse the labels and author associated with a Pull Request - // (with the exception of `bump:` and `scope:`) for all - // commits associated with the PR. - if (commit.hexsha) { - const pullRequests = yield (0, github_2.getAssociatedPullRequests)(commit.hexsha); - if (pullRequests.length > 0) { - const pullRequest = pullRequests[0]; - // Append the labels of the associated Pull Request - // NOTE: we ignore the version bump and scope label on the PR as this is - // and instead rely on version bump label associated with this - // commit. - labels = labels.concat(pullRequest.labels - .filter(label => !Label.isCategory(label.name, "bump") && - !Label.isCategory(label.name, "scope")) - .map(label => label.name)); - // Check if the author of the Pull Request is part of the exclude list - if (pullRequest.user && - ((_c = (_b = config.changelog.exclude) === null || _b === void 0 ? void 0 : _b.authors) === null || _c === void 0 ? void 0 : _c.includes(pullRequest.user.login))) { - continue; - } - } } - // Check if any of the labels is part of the global exclusion list - if (labels.some(label => { var _a, _b; return (_b = (_a = config.changelog.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { + // Validate whether the commit matches any of the inclusion patterns + if (!labels + .concat([bumpLabel, "*"]) + .some(label => { var _a; return (_a = category.labels) === null || _a === void 0 ? void 0 : _a.includes(label); })) { continue; } - // Either group commits per Conventional Commit scope, or group them all - // together (*) - const scope = config.changelog.group === "scope" - ? ((_d = commit === null || commit === void 0 ? void 0 : commit.scope) === null || _d === void 0 ? void 0 : _d.toLowerCase()) || "*" - : "*"; - changelog.set(scope, (_e = changelog.get(scope)) !== null && _e !== void 0 ? _e : new Map()); - for (const category of config.changelog.categories) { - // Apply all exclusion patterns from Pull Request metadata on Category - if (labels.some(label => { var _a, _b; return (_b = (_a = category.exclude) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.includes(label); })) { - continue; - } - // Validate whether the commit matches any of the inclusion patterns - if (!labels - .concat([bumpLabel, "*"]) - .some(label => { var _a; return (_a = category.labels) === null || _a === void 0 ? void 0 : _a.includes(label); })) { - continue; - } - if (((_f = changelog.get(scope)) === null || _f === void 0 ? void 0 : _f.get(category.title)) === undefined) { - (_g = changelog.get(scope)) === null || _g === void 0 ? void 0 : _g.set(category.title, []); - } - (_j = (_h = changelog - .get(scope)) === null || _h === void 0 ? void 0 : _h.get(category.title)) === null || _j === void 0 ? void 0 : _j.push(yield generateChangelogEntry(commit)); - break; + if (((_f = changelog.get(scope)) === null || _f === void 0 ? void 0 : _f.get(category.title)) === undefined) { + (_g = changelog.get(scope)) === null || _g === void 0 ? void 0 : _g.set(category.title, []); } + (_j = (_h = changelog + .get(scope)) === null || _h === void 0 ? void 0 : _h.get(category.title)) === null || _j === void 0 ? void 0 : _j.push(await generateChangelogEntry(commit)); + break; } - // Sort changelog, with the all (*) scope always as last item - const sortedChangelog = [...changelog].sort((a, b) => a[0] === "*" ? 1 : b[0] === "*" ? -1 : a[0].localeCompare(b[0])); - // Generate Changelog - let formattedChangelog = "## What's changed\n"; - for (const [scope, categories] of sortedChangelog) { - const isGrouped = scope !== "*"; - if (isGrouped) { - formattedChangelog += `### ${capitalizeFirstLetter(scope)}\n`; - } - for (const [category, messages] of categories) { - if (messages.length > 0) { - formattedChangelog += isGrouped - ? `#### ${category}\n` - : `### ${category}\n`; - for (const message of messages) { - formattedChangelog += `* ${message}\n`; - } + } + // Sort changelog, with the all (*) scope always as last item + const sortedChangelog = [...changelog].sort((a, b) => a[0] === "*" ? 1 : b[0] === "*" ? -1 : a[0].localeCompare(b[0])); + // Generate Changelog + let formattedChangelog = "## What's changed\n"; + for (const [scope, categories] of sortedChangelog) { + const isGrouped = scope !== "*"; + if (isGrouped) { + formattedChangelog += `### ${capitalizeFirstLetter(scope)}\n`; + } + for (const [category, messages] of categories) { + if (messages.length > 0) { + formattedChangelog += isGrouped + ? `#### ${category}\n` + : `### ${category}\n`; + for (const message of messages) { + formattedChangelog += `* ${message}\n`; } } } - const { owner, repo } = github_1.context.repo; - const diffRange = `${startVersion}...${endVersion || github_1.context.sha.substring(0, 8)}`; - formattedChangelog += - `\n\n*Diff since last release: ` + - `[${diffRange}](https://github.com/${owner}/${repo}/compare/${diffRange})*`; - return formattedChangelog; - }); + } + const { owner, repo } = github_1.context.repo; + const diffRange = `${startVersion}...${endVersion || github_1.context.sha.substring(0, 8)}`; + formattedChangelog += + `\n\n*Diff since last release: ` + + `[${diffRange}](https://github.com/${owner}/${repo}/compare/${diffRange})*`; + return formattedChangelog; } exports.generateChangelogForCommits = generateChangelogForCommits; /** * Returns a markdown-formatted changelog, based on the info contained * in the provided `IVersionBumpTypeAndMessages`. */ -function generateChangelog(bump) { +async function generateChangelog(bump) { var _a, _b, _c, _d, _e; - return __awaiter(this, void 0, void 0, function* () { - return yield generateChangelogForCommits((_b = (_a = bump.foundVersion) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", (_e = (_d = (_c = bump.foundVersion) === null || _c === void 0 ? void 0 : _c.bump(bump.requiredBump, bump.initialDevelopment)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : "", bump.processedCommits - .map(c => c.message) - .filter(c => c)); - }); + return await generateChangelogForCommits((_b = (_a = bump.foundVersion) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "", (_e = (_d = (_c = bump.foundVersion) === null || _c === void 0 ? void 0 : _c.bump(bump.requiredBump, bump.initialDevelopment)) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : "", bump.processedCommits + .map(c => c.message) + .filter(c => c)); } exports.generateChangelog = generateChangelog; @@ -35090,11 +35036,7 @@ const VERSION_SCHEMES = ["semver", "sdkver"]; /** * This function takes two values and throws when their types don't match. */ -function verifyTypeMatches(name, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeToTest, -// eslint-disable-next-line @typescript-eslint/no-explicit-any -typeItShouldBe) { +function verifyTypeMatches(name, typeToTest, typeItShouldBe) { if (typeof typeToTest !== typeof typeItShouldBe) { throw new Error(`Incorrect type '${typeof typeToTest}' for '${name}', must be '${typeof typeItShouldBe}'`); } @@ -35109,9 +35051,19 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } + setRuleActivationStatus(ruleId, enabled) { + const rule = this.rules.get(ruleId); + if (rule !== undefined) { + rule.enabled = enabled; + } + else { + core.warning(`Rule "${ruleId}" is unknown; enabling or disabling it has no effect.`); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any loadFromData(data) { - var _a, _b; - var _c; + var _a, _b, _c; + var _d; for (const key in data) { if (!CONFIG_ITEMS.includes(key)) { throw new Error(`Unknown configuration item '${key}' detected!`); @@ -35128,12 +35080,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - if (item in this.rules) { - this.rules[item].enabled = key === "enable"; - } - else { - core.warning(`Rule "${item}" is unknown; enabling or disabling it has no effect.`); - } + this.setRuleActivationStatus(item, key === "enable"); } } else { @@ -35170,20 +35117,24 @@ class Configuration { this.tags[typ] = { description: typeValue, bump: false }; break; case "object": - for (const entry of Object.keys(typeValue)) { - if (["description", "bump"].includes(entry)) { - if (entry === "description") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + { + const tagObject = (_a = this.tags[typ]) !== null && _a !== void 0 ? _a : {}; + for (const entry of Object.keys(typeValue)) { + if (["description", "bump"].includes(entry)) { + if (entry === "description") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], ""); + tagObject.description = typeValue[entry]; + } + else if (entry === "bump") { + verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + tagObject.bump = typeValue[entry]; + } } - else if (entry === "bump") { - verifyTypeMatches(`${typ}.${entry}`, typeValue[entry], true); + else { + core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } - this.tags[typ] = this.tags[typ] ? this.tags[typ] : {}; - this.tags[typ][entry] = typeValue[entry]; - } - else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } + this.tags[typ] = tagObject; } break; default: @@ -35202,11 +35153,11 @@ class Configuration { let desc = ""; // Use the default description if it's one of the default tags if (typ in DEFAULT_ACCEPTED_TAGS) { - desc = (_a = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _a !== void 0 ? _a : ""; + desc = (_b = DEFAULT_ACCEPTED_TAGS[typ].description) !== null && _b !== void 0 ? _b : ""; } this.tags[typ].description = desc; } - (_b = (_c = this.tags[typ]).bump) !== null && _b !== void 0 ? _b : (_c.bump = false); + (_c = (_d = this.tags[typ]).bump) !== null && _c !== void 0 ? _c : (_d.bump = false); } break; case "allowed-branches": @@ -35321,10 +35272,10 @@ class Configuration { this.rules = new Map(); this.sdkverCreateReleaseBranches = undefined; for (const rule of rules_1.ALL_RULES) { - this.rules[rule.id] = { + this.rules.set(rule.id, { description: rule.description, enabled: rule.default, - }; + }); } if (fs.existsSync(configPath)) { const data = yaml.parse(fs.readFileSync(configPath, "utf8")); @@ -35444,22 +35395,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __asyncValues = (this && this.__asyncValues) || function (o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.createBranch = exports.getCommitsBetweenRefs = exports.currentHeadMatchesTag = exports.getContent = exports.updateLabels = exports.getAssociatedPullRequests = exports.getLatestTags = exports.getShaForTag = exports.matchTagsToCommits = exports.getReleaseConfiguration = exports.getConfig = exports.createTag = exports.updateDraftRelease = exports.getRelease = exports.createRelease = exports.getPullRequest = exports.getCommitsInPR = exports.getPullRequestTitle = exports.getRunNumber = exports.getPullRequestId = exports.isPullRequestEvent = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -35510,10 +35445,8 @@ exports.getRunNumber = getRunNumber; /** * The current pull request's title */ -function getPullRequestTitle() { - return __awaiter(this, void 0, void 0, function* () { - return (yield getPullRequest(getPullRequestId())).title; - }); +async function getPullRequestTitle() { + return (await getPullRequest(getPullRequestId())).title; } exports.getPullRequestTitle = getPullRequestTitle; /** @@ -35521,12 +35454,13 @@ exports.getPullRequestTitle = getPullRequestTitle; * @param pullRequestId GitHub pull request ID * @returns ICommit[] List of ICommit objects */ -function getCommitsInPR(pullRequestId) { - return __awaiter(this, void 0, void 0, function* () { - // Retrieve commits from provided pull request - const { data: commits } = yield getOctokit().rest.pulls.listCommits(Object.assign(Object.assign({}, github.context.repo), { pull_number: pullRequestId })); - return githubCommitsAsICommits(commits); +async function getCommitsInPR(pullRequestId) { + // Retrieve commits from provided pull request + const { data: commits } = await getOctokit().rest.pulls.listCommits({ + ...github.context.repo, + pull_number: pullRequestId, }); + return githubCommitsAsICommits(commits); } exports.getCommitsInPR = getCommitsInPR; /** @@ -35534,11 +35468,12 @@ exports.getCommitsInPR = getCommitsInPR; * @param pullRequestId GitHub Pullrequest ID * @returns Pull Request */ -function getPullRequest(pullRequestId) { - return __awaiter(this, void 0, void 0, function* () { - const { data: pr } = yield getOctokit().rest.pulls.get(Object.assign(Object.assign({}, github.context.repo), { pull_number: pullRequestId })); - return pr; +async function getPullRequest(pullRequestId) { + const { data: pr } = await getOctokit().rest.pulls.get({ + ...github.context.repo, + pull_number: pullRequestId, }); + return pr; } exports.getPullRequest = getPullRequest; /** @@ -35548,11 +35483,15 @@ exports.getPullRequest = getPullRequest; * @param body The release's text description * @param draft Create this release as a 'draft' release */ -function createRelease(tagName, commitish, body, draft, prerelease) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.repos.createRelease(Object.assign(Object.assign({}, github.context.repo), { tag_name: tagName, target_commitish: commitish, name: tagName, body, - draft, - prerelease })); +async function createRelease(tagName, commitish, body, draft, prerelease) { + await getOctokit().rest.repos.createRelease({ + ...github.context.repo, + tag_name: tagName, + target_commitish: commitish, + name: tagName, + body, + draft, + prerelease, }); } exports.createRelease = createRelease; @@ -35564,50 +35503,50 @@ exports.createRelease = createRelease; * * Returns an object {id, name}, or `undefined` if no tag was found. */ -function getRelease(params) { - return __awaiter(this, void 0, void 0, function* () { - core.info(`getRelease: finding ${params.draftOnly ? "draft " : ""}release with the prefix: ${params.prefixToMatch}`); - const octo = getOctokit(); - const result = (yield octo.paginate(octo.rest.repos.listReleases, Object.assign({}, github.context.repo))).map(r => ({ isDraft: r.draft, tagName: r.tag_name, id: r.id })); - core.debug(`getRelease: listReleases returned:\n${JSON.stringify(result)}`); - /** - * We need to: - * - only consider releases starting with the provided prefix, draft and - * release parameters - * - consider the major/minor constraint, if provided - * - _NOT_ rely on the temporal data; the precendence of the existing tags - * shall determined according to a "SemVer-esque prerelease", that is: - * * componentX-1.2.3-9 < componentX-1.2.3-10 - * - return the highest-precedence item - */ - const releaseList = result - .filter(r => r.isDraft === params.draftOnly) - .filter(r => { - const asSemVer = semver_1.SemVer.fromString(r.tagName); - return ((asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prefix) === params.prefixToMatch && - (params.fullReleasesOnly ? (asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prerelease) === "" : true)); - }) - .map(r => ({ id: r.id, name: r.tagName })) - .sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); - core.debug(`getRelease: sorted list of releases:\n${JSON.stringify(releaseList)}`); - if (params.constraint) { - // We're sorted by precedence, highest last, so let's reverse it and we can - // take the first major/minor version lower than the constraint we encounter. - releaseList.reverse(); - for (const r of releaseList) { - core.debug(`checking release ${r.name} against constraint ` + - `${params.constraint.major}.${params.constraint.minor}.*`); - const sv = semver_1.SemVer.fromString(r.name); - if (sv && - sv.major <= params.constraint.major && - sv.minor <= params.constraint.minor) { - return r; - } +async function getRelease(params) { + core.info(`getRelease: finding ${params.draftOnly ? "draft " : ""}release with the prefix: ${params.prefixToMatch}`); + const octo = getOctokit(); + const result = (await octo.paginate(octo.rest.repos.listReleases, { + ...github.context.repo, + })).map(r => ({ isDraft: r.draft, tagName: r.tag_name, id: r.id })); + core.debug(`getRelease: listReleases returned:\n${JSON.stringify(result)}`); + /** + * We need to: + * - only consider releases starting with the provided prefix, draft and + * release parameters + * - consider the major/minor constraint, if provided + * - _NOT_ rely on the temporal data; the precendence of the existing tags + * shall determined according to a "SemVer-esque prerelease", that is: + * * componentX-1.2.3-9 < componentX-1.2.3-10 + * - return the highest-precedence item + */ + const releaseList = result + .filter(r => r.isDraft === params.draftOnly) + .filter(r => { + const asSemVer = semver_1.SemVer.fromString(r.tagName); + return ((asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prefix) === params.prefixToMatch && + (params.fullReleasesOnly ? (asSemVer === null || asSemVer === void 0 ? void 0 : asSemVer.prerelease) === "" : true)); + }) + .map(r => ({ id: r.id, name: r.tagName })) + .sort((lhs, rhs) => semver_1.SemVer.sortSemVer(lhs.name, rhs.name)); + core.debug(`getRelease: sorted list of releases:\n${JSON.stringify(releaseList)}`); + if (params.constraint) { + // We're sorted by precedence, highest last, so let's reverse it and we can + // take the first major/minor version lower than the constraint we encounter. + releaseList.reverse(); + for (const r of releaseList) { + core.debug(`checking release ${r.name} against constraint ` + + `${params.constraint.major}.${params.constraint.minor}.*`); + const sv = semver_1.SemVer.fromString(r.name); + if (sv && + sv.major <= params.constraint.major && + sv.minor <= params.constraint.minor) { + return r; } - return; } - return releaseList.pop(); - }); + return; + } + return releaseList.pop(); } exports.getRelease = getRelease; /** @@ -35615,13 +35554,20 @@ exports.getRelease = getRelease; * * Returns `true` if successful */ -function updateDraftRelease(id, newName, tagName, sha, bodyContents, isDraft = true, isPrerelease = false) { - return __awaiter(this, void 0, void 0, function* () { - core.debug(`Update existing draft release with id ${id} to ${newName} (${tagName}) sha: ${sha}, ` + - `and body below:\n${bodyContents}`); - const result = yield getOctokit().rest.repos.updateRelease(Object.assign(Object.assign({}, github.context.repo), { release_id: id, target_commitish: sha, draft: isDraft, prerelease: isPrerelease, body: bodyContents, name: newName, tag_name: tagName })); - return result.status < 400; +async function updateDraftRelease(id, newName, tagName, sha, bodyContents, isDraft = true, isPrerelease = false) { + core.debug(`Update existing draft release with id ${id} to ${newName} (${tagName}) sha: ${sha}, ` + + `and body below:\n${bodyContents}`); + const result = await getOctokit().rest.repos.updateRelease({ + ...github.context.repo, + release_id: id, + target_commitish: sha, + draft: isDraft, + prerelease: isPrerelease, + body: bodyContents, + name: newName, + tag_name: tagName, }); + return result.status < 400; } exports.updateDraftRelease = updateDraftRelease; /** @@ -35629,9 +35575,11 @@ exports.updateDraftRelease = updateDraftRelease; * @param tagName Name of the tag * @param sha The SHA1 value of the tag */ -function createTag(tagName, sha) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.git.createRef(Object.assign(Object.assign({}, github.context.repo), { ref: tagName.startsWith("refs/tags/") ? tagName : `refs/tags/${tagName}`, sha })); +async function createTag(tagName, sha) { + await getOctokit().rest.git.createRef({ + ...github.context.repo, + ref: tagName.startsWith("refs/tags/") ? tagName : `refs/tags/${tagName}`, + sha, }); } exports.createTag = createTag; @@ -35639,29 +35587,25 @@ exports.createTag = createTag; * Downloads the requested configuration file in case it exists. * @param path Path towards the Commisery configuration file */ -function getConfig(path) { - return __awaiter(this, void 0, void 0, function* () { - const config = yield getContent(path); - if (config !== undefined) { - fs.writeFileSync(".commisery.yml", config); - } - }); +async function getConfig(path) { + const config = await getContent(path); + if (config !== undefined) { + fs.writeFileSync(".commisery.yml", config); + } } exports.getConfig = getConfig; /** * Downloads the release configuration (.github/release.y[a]ml) in the repository. * Return empty configuration if the file(s) do not exist. */ -function getReleaseConfiguration() { - return __awaiter(this, void 0, void 0, function* () { - for (const path of [".github/release.yml", ".github/release.yaml"]) { - const content = yield getContent(path); - if (content !== undefined) { - return content; - } +async function getReleaseConfiguration() { + for (const path of [".github/release.yml", ".github/release.yaml"]) { + const content = await getContent(path); + if (content !== undefined) { + return content; } - return ""; - }); + } + return ""; } exports.getReleaseConfiguration = getReleaseConfiguration; /** @@ -35675,55 +35619,37 @@ exports.getReleaseConfiguration = getReleaseConfiguration; * Alternatively, if no match could be made, returns `null` along with all * the commits encountered. */ -function matchTagsToCommits(sha, matcher) { - var _a, e_1, _b, _c; - return __awaiter(this, void 0, void 0, function* () { - const octo = getOctokit(); - const commitList = []; - let match = null; - sha = sha !== null && sha !== void 0 ? sha : github.context.sha; - try { - for (var _d = true, _e = __asyncValues(octo.paginate.iterator(octo.rest.repos.listCommits, Object.assign(Object.assign({}, github.context.repo), { sha }))), _f; _f = yield _e.next(), _a = _f.done, !_a;) { - _c = _f.value; - _d = false; - try { - const resp = _c; - for (const commit of resp.data) { - match = matcher(commit.commit.message, commit.sha); - if (match) { - core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); - return [match, commitList]; - } - commitList.push({ message: commit.commit.message, sha: commit.sha }); - } - } - finally { - _d = true; - } +async function matchTagsToCommits(sha, matcher) { + const octo = getOctokit(); + const commitList = []; + let match = null; + sha = sha !== null && sha !== void 0 ? sha : github.context.sha; + for await (const resp of octo.paginate.iterator(octo.rest.repos.listCommits, { + ...github.context.repo, + sha, + })) { + for (const commit of resp.data) { + match = matcher(commit.commit.message, commit.sha); + if (match) { + core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); + return [match, commitList]; } + commitList.push({ message: commit.commit.message, sha: commit.sha }); } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (!_d && !_a && (_b = _e.return)) yield _b.call(_e); - } - finally { if (e_1) throw e_1.error; } - } - return [match, commitList]; - }); + } + return [match, commitList]; } exports.matchTagsToCommits = matchTagsToCommits; /** * Get the commit sha associated with the provided tag, or `undefined` if * the tag doesn't exist. */ -function getShaForTag(tag) { +async function getShaForTag(tag) { var _a; - return __awaiter(this, void 0, void 0, function* () { - if (!tag.startsWith("refs/tags/")) { - tag = `refs/tags/${tag}`; - } - const result = yield getOctokit().graphql(` + if (!tag.startsWith("refs/tags/")) { + tag = `refs/tags/${tag}`; + } + const result = await getOctokit().graphql(` { repository(owner: "${github.context.repo.owner}", name: "${github.context.repo.repo}") { ref(qualifiedName: "${tag}") { @@ -35734,16 +35660,14 @@ function getShaForTag(tag) { } } `); - return (_a = result.repository.ref) === null || _a === void 0 ? void 0 : _a.target.oid; - }); + return (_a = result.repository.ref) === null || _a === void 0 ? void 0 : _a.target.oid; } exports.getShaForTag = getShaForTag; /** * Retrieve `pageSize` tags in the current repo */ -function getLatestTags(pageSize) { - return __awaiter(this, void 0, void 0, function* () { - const result = yield getOctokit().graphql(` +async function getLatestTags(pageSize) { + const result = await getOctokit().graphql(` { repository(owner: "${github.context.repo.owner}", name: "${github.context.repo.repo}") { refs( @@ -35768,96 +35692,107 @@ function getLatestTags(pageSize) { } } `); - const tagList = result.repository.refs.edges.map(x => ({ - name: x.node.name, - commitSha: x.node.reftarget.tagtarget - ? x.node.reftarget.tagtarget.commitsha - : x.node.reftarget.commitsha, - })); - return tagList; - }); + const tagList = result.repository.refs.edges.map(x => ({ + name: x.node.name, + commitSha: x.node.reftarget.tagtarget + ? x.node.reftarget.tagtarget.commitsha + : x.node.reftarget.commitsha, + })); + return tagList; } exports.getLatestTags = getLatestTags; /** * Retrieve the Pull Requests associated with the specified commit SHA */ -function getAssociatedPullRequests(sha) { - return __awaiter(this, void 0, void 0, function* () { - try { - const { data: prs } = yield getOctokit().rest.repos.listPullRequestsAssociatedWithCommit(Object.assign(Object.assign({}, github.context.repo), { commit_sha: sha })); - return prs; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } - catch (error) { - if (error.message !== "Resource not accessible by integration") { - throw error; - } +async function getAssociatedPullRequests(sha) { + try { + const { data: prs } = await getOctokit().rest.repos.listPullRequestsAssociatedWithCommit({ + ...github.context.repo, + commit_sha: sha, + }); + return prs; + } + catch (error) { + if (error instanceof Error && + error.message === "Resource not accessible by integration") { return []; } - }); + throw error; + } } exports.getAssociatedPullRequests = getAssociatedPullRequests; /** * Updates the Pull Request (issue) labels */ -function updateLabels(labels) { - return __awaiter(this, void 0, void 0, function* () { - const issueId = getPullRequestId(); - // Retrieve current labels - const { data: pullRequestLabels } = yield getOctokit().rest.issues.listLabelsOnIssue(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId })); - try { - // Remove all bump, type and initial development labels - for (const label of pullRequestLabels) { - if (Label.isManaged(label.name)) { - // Check if the label should remain, if not, remove the label from the Pull Request - if (labels.includes(label.name)) { - labels = labels.filter(l => l !== label.name); - } - else { - yield getOctokit().rest.issues.removeLabel(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId, name: label.name })); - } +async function updateLabels(labels) { + const issueId = getPullRequestId(); + // Retrieve current labels + const { data: pullRequestLabels } = await getOctokit().rest.issues.listLabelsOnIssue({ + ...github.context.repo, + issue_number: issueId, + }); + try { + // Remove all bump, type and initial development labels + for (const label of pullRequestLabels) { + if (Label.isManaged(label.name)) { + // Check if the label should remain, if not, remove the label from the Pull Request + if (labels.includes(label.name)) { + labels = labels.filter(l => l !== label.name); + } + else { + await getOctokit().rest.issues.removeLabel({ + ...github.context.repo, + issue_number: issueId, + name: label.name, + }); } } - if (labels.length > 0) { - // Add new label if it does not yet exist - yield getOctokit().rest.issues.addLabels(Object.assign(Object.assign({}, github.context.repo), { issue_number: issueId, labels })); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any } - catch (error) { - if (error.message !== "Resource not accessible by integration") { - throw error; - } + if (labels.length > 0) { + // Add new label if it does not yet exist + await getOctokit().rest.issues.addLabels({ + ...github.context.repo, + issue_number: issueId, + labels, + }); + } + } + catch (error) { + if (error instanceof Error && + error.message === "Resource not accessible by integration") { core.warning("Unable to update Pull Request labels, did you provide the `write` permission for `issues` and `pull-requests`?"); + return; } - }); + throw error; + } } exports.updateLabels = updateLabels; /** * Downloads and returns the contents of the specified file path. */ -function getContent(path) { - return __awaiter(this, void 0, void 0, function* () { - try { - const response = yield getOctokit().rest.repos.getContent(Object.assign(Object.assign({}, github.context.repo), { path, ref: github.context.ref })); - if ("content" in response.data) { - return Buffer.from(response.data.content, "base64").toString("utf8"); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } - catch (error) { - core.debug(error.message); +async function getContent(path) { + try { + const response = await getOctokit().rest.repos.getContent({ + ...github.context.repo, + path, + ref: github.context.ref, + }); + if ("content" in response.data) { + return Buffer.from(response.data.content, "base64").toString("utf8"); } - }); + } + catch (error) { + // We intentially capture all failures and return `undefined` in case the + // file does not exist or cannot be accessed. + core.debug(error.message); + } } exports.getContent = getContent; /** * Returns `true` if `context.sha` matches the sha of the tag `tagName`. */ -function currentHeadMatchesTag(tagName) { - return __awaiter(this, void 0, void 0, function* () { - return (yield getShaForTag(tagName)) === github.context.sha; - }); +async function currentHeadMatchesTag(tagName) { + return (await getShaForTag(tagName)) === github.context.sha; } exports.currentHeadMatchesTag = currentHeadMatchesTag; /** @@ -35867,11 +35802,12 @@ exports.currentHeadMatchesTag = currentHeadMatchesTag; * * Returns a list ICommits representing `baseRef...compRef`. */ -function getCommitsBetweenRefs(baseRef, compRef) { - return __awaiter(this, void 0, void 0, function* () { - const { data: resp } = yield getOctokit().rest.repos.compareCommitsWithBasehead(Object.assign(Object.assign({}, github.context.repo), { basehead: `${baseRef}...${compRef !== null && compRef !== void 0 ? compRef : github.context.sha}` })); - return githubCommitsAsICommits(resp.commits); +async function getCommitsBetweenRefs(baseRef, compRef) { + const { data: resp } = await getOctokit().rest.repos.compareCommitsWithBasehead({ + ...github.context.repo, + basehead: `${baseRef}...${compRef !== null && compRef !== void 0 ? compRef : github.context.sha}`, }); + return githubCommitsAsICommits(resp.commits); } exports.getCommitsBetweenRefs = getCommitsBetweenRefs; /** @@ -35879,9 +35815,11 @@ exports.getCommitsBetweenRefs = getCommitsBetweenRefs; * @param name The name of the branch to be created * @param sha The commit hash of the branch-off point */ -function createBranch(name, sha) { - return __awaiter(this, void 0, void 0, function* () { - yield getOctokit().rest.git.createRef(Object.assign(Object.assign({}, github.context.repo), { ref: name.startsWith("refs/heads/") ? name : `refs/heads/${name}`, sha })); +async function createBranch(name, sha) { + await getOctokit().rest.git.createRef({ + ...github.context.repo, + ref: name.startsWith("refs/heads/") ? name : `refs/heads/${name}`, + sha, }); } exports.createBranch = createBranch; @@ -35966,7 +35904,7 @@ var LlvmLevel; LlvmLevel["ERROR"] = "ERROR"; LlvmLevel["WARNING"] = "WARNING"; LlvmLevel["NOTE"] = "NOTE"; -})(LlvmLevel = exports.LlvmLevel || (exports.LlvmLevel = {})); +})(LlvmLevel || (exports.LlvmLevel = LlvmLevel = {})); // eslint-disable-next-line no-shadow var TextFormat; (function (TextFormat) { @@ -36119,8 +36057,8 @@ const logging_1 = __nccwpck_require__(1517); */ function validateRules(message, config) { const errors = []; - const disabledRules = Object.entries(config.rules) - .filter(item => !item[1]["enabled"]) + const disabledRules = Array.from(config.rules) + .filter(item => item[1].enabled === false) .map(item => item[0]); for (const rule of exports.ALL_RULES) { try { @@ -36131,10 +36069,9 @@ function validateRules(message, config) { catch (error) { if (error instanceof logging_1.LlvmError) { errors.push(error); + continue; } - else { - throw error; - } + throw error; } } return errors; @@ -36855,7 +36792,7 @@ var SemVerType; SemVerType[SemVerType["PATCH"] = 1] = "PATCH"; SemVerType[SemVerType["MINOR"] = 2] = "MINOR"; SemVerType[SemVerType["MAJOR"] = 3] = "MAJOR"; -})(SemVerType = exports.SemVerType || (exports.SemVerType = {})); +})(SemVerType || (exports.SemVerType = SemVerType = {})); class SemVer { constructor({ major, minor, patch, prerelease = "", build = "", prefix = "", }) { this.major = major; @@ -36866,7 +36803,10 @@ class SemVer { this.prefix = prefix; } static copy(semver) { - return new SemVer(Object.assign({ build: semver.build }, semver)); + return new SemVer({ + build: semver.build, + ...semver, + }); } get build() { return this._build; @@ -37136,15 +37076,6 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validatePrTitleBump = exports.validatePrTitle = exports.validateCommitsInCurrentPR = exports.processCommits = exports.outputCommitListErrors = void 0; const core = __importStar(__nccwpck_require__(2186)); @@ -37224,11 +37155,13 @@ function processCommits(commits, config) { message: undefined, errors: error.errors, }); + continue; } else if (error instanceof errors_1.MergeCommitError || error instanceof errors_1.FixupCommitError) { continue; } + throw error; } } return results; @@ -37237,128 +37170,121 @@ exports.processCommits = processCommits; /** * Validates all commit messages in the current pull request. */ -function validateCommitsInCurrentPR(config) { +async function validateCommitsInCurrentPR(config) { var _a; - return __awaiter(this, void 0, void 0, function* () { - const commits = yield (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); - const results = processCommits(commits, config); - const passResults = results.filter(c => c.errors.length === 0); - const failResults = results.filter(c => c.errors.length !== 0); - if (passResults.length > 0) { - core.info(`✅ ${failResults.length === 0 ? "All " : ""}${passResults.length}` + - ` of the pull request's commits are valid Conventional Commits`); - for (const c of passResults) { - core.startGroup(`✅ Commit (${c.input.sha.slice(0, 8)}): ${(_a = c.message) === null || _a === void 0 ? void 0 : _a.subject}`); - core.info(c.input.message); - core.endGroup(); - } - } - if (failResults.length > 0) { - core.info(""); // for vertical whitespace - core.setFailed(`${failResults.length} of the pull request's commits are not valid Conventional Commits`); - outputCommitListErrors(failResults, true); + const commits = await (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); + const results = processCommits(commits, config); + const passResults = results.filter(c => c.errors.length === 0); + const failResults = results.filter(c => c.errors.length !== 0); + if (passResults.length > 0) { + core.info(`✅ ${failResults.length === 0 ? "All " : ""}${passResults.length}` + + ` of the pull request's commits are valid Conventional Commits`); + for (const c of passResults) { + core.startGroup(`✅ Commit (${c.input.sha.slice(0, 8)}): ${(_a = c.message) === null || _a === void 0 ? void 0 : _a.subject}`); + core.info(c.input.message); + core.endGroup(); } - return { - compliant: failResults.length === 0, - messages: passResults.map(r => r.message), - }; - }); + } + if (failResults.length > 0) { + core.info(""); // for vertical whitespace + core.setFailed(`${failResults.length} of the pull request's commits are not valid Conventional Commits`); + outputCommitListErrors(failResults, true); + } + return { + compliant: failResults.length === 0, + messages: passResults.map(r => r.message), + }; } exports.validateCommitsInCurrentPR = validateCommitsInCurrentPR; /** * Validates the pull request title and, if compliant, returns it as a * ConventionalCommitMessage object. */ -function validatePrTitle(_) { - return __awaiter(this, void 0, void 0, function* () { - const prTitleText = yield (0, github_1.getPullRequestTitle)(); - let errors = []; - let conventionalCommitMessage; - core.info(""); // for vertical whitespace - let errorMessage = "The pull request title is not compliant " + - "with the Conventional Commits specification"; - try { - conventionalCommitMessage = new commit_1.ConventionalCommitMessage(prTitleText); - } - catch (error) { - if (error instanceof errors_1.ConventionalCommitError) { - errors = error.errors; - } - else { - if (error instanceof errors_1.MergeCommitError) { - errorMessage = `${errorMessage} (it describes a merge commit)`; - } - else if (error instanceof errors_1.FixupCommitError) { - errorMessage = `${errorMessage} (it describes a fixup commit)`; - } - core.setFailed(errorMessage); - return undefined; - } +async function validatePrTitle(_) { + const prTitleText = await (0, github_1.getPullRequestTitle)(); + let errors = []; + let conventionalCommitMessage; + core.info(""); // for vertical whitespace + let errorMessage = "The pull request title is not compliant " + + "with the Conventional Commits specification"; + try { + conventionalCommitMessage = new commit_1.ConventionalCommitMessage(prTitleText); + } + catch (error) { + if (error instanceof errors_1.ConventionalCommitError) { + errors = error.errors; } - if (errors.length > 0) { + else if (error instanceof errors_1.MergeCommitError || + error instanceof errors_1.FixupCommitError) { + errorMessage = `${errorMessage} (it describes a ${error instanceof errors_1.MergeCommitError ? "merge" : "fixup"} commit)`; core.setFailed(errorMessage); - outputCommitErrors(prTitleText, errors, undefined, true); + return undefined; } else { - core.startGroup(`✅ The pull request title is compliant with the Conventional Commits specification`); - core.info(prTitleText); - core.endGroup(); + throw error; } - return conventionalCommitMessage; - }); + } + if (errors.length > 0) { + core.setFailed(errorMessage); + outputCommitErrors(prTitleText, errors, undefined, true); + } + else { + core.startGroup(`✅ The pull request title is compliant with the Conventional Commits specification`); + core.info(prTitleText); + core.endGroup(); + } + return conventionalCommitMessage; } exports.validatePrTitle = validatePrTitle; /** * Validates bump level consistency between the PR title and its commits. * This implies that the PR title must comply with the Conventional Commits spec. */ -function validatePrTitleBump(config) { +async function validatePrTitleBump(config) { var _a, _b; - return __awaiter(this, void 0, void 0, function* () { - const prTitleText = yield (0, github_1.getPullRequestTitle)(); - const commits = yield (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); - const prTitle = yield validatePrTitle(config); - const baseError = "Cannot validate the consistency of bump levels between PR title and PR commits"; - if (prTitle === undefined) { - core.warning(`${baseError}, as PR title is not a valid Conventional Commits message.`); - return false; - } - if (commits.length === 0) { - core.warning("No commits found in this pull request."); - return true; - } - core.info(""); // for vertical whitespace - const results = processCommits(commits, config); - if (results.some(c => c.errors.length !== 0)) { - // Abort if the list contains any non-compliant commits; bump level - // validation only really makes sense if all commits are found to - // be compliant. - core.warning(`${baseError}, as the PR contains non-compliant commits`); - return false; - } - const highestBump = (_b = (_a = results.reduce((acc, val) => { - var _a, _b, _c, _d; - const accb = (_b = (_a = acc.message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; - const valb = (_d = (_c = val.message) === null || _c === void 0 ? void 0 : _c.bump) !== null && _d !== void 0 ? _d : semver_1.SemVerType.NONE; - return accb > valb ? acc : val; - }).message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; - if (highestBump !== prTitle.bump) { - const commitSubjects = results - .map(r => { var _a; return (_a = r.message) === null || _a === void 0 ? void 0 : _a.subject; }) - .filter(x => x !== undefined); - core.setFailed("The PR title's bump level is not consistent with its commits.\n" + - `The PR title type ${prTitle.type} represents bump level ` + - `${semver_1.SemVerType[prTitle.bump]}, while the highest bump in the ` + - `commits is ${semver_1.SemVerType[highestBump]}.\n` + - `PR title: "${prTitleText}"\n` + - `Commit list:\n${` - ${commitSubjects.join("\n - ")}`}`); - return false; - } - else { - core.info(`✅ The pull request title's bump level is consistent with the PR's commits`); - return true; - } - }); + const prTitleText = await (0, github_1.getPullRequestTitle)(); + const commits = await (0, github_1.getCommitsInPR)((0, github_1.getPullRequestId)()); + const prTitle = await validatePrTitle(config); + const baseError = "Cannot validate the consistency of bump levels between PR title and PR commits"; + if (prTitle === undefined) { + core.warning(`${baseError}, as PR title is not a valid Conventional Commits message.`); + return false; + } + if (commits.length === 0) { + core.warning("No commits found in this pull request."); + return true; + } + core.info(""); // for vertical whitespace + const results = processCommits(commits, config); + if (results.some(c => c.errors.length !== 0)) { + // Abort if the list contains any non-compliant commits; bump level + // validation only really makes sense if all commits are found to + // be compliant. + core.warning(`${baseError}, as the PR contains non-compliant commits`); + return false; + } + const highestBump = (_b = (_a = results.reduce((acc, val) => { + var _a, _b, _c, _d; + const accb = (_b = (_a = acc.message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; + const valb = (_d = (_c = val.message) === null || _c === void 0 ? void 0 : _c.bump) !== null && _d !== void 0 ? _d : semver_1.SemVerType.NONE; + return accb > valb ? acc : val; + }).message) === null || _a === void 0 ? void 0 : _a.bump) !== null && _b !== void 0 ? _b : semver_1.SemVerType.NONE; + if (highestBump !== prTitle.bump) { + const commitSubjects = results + .map(r => { var _a; return (_a = r.message) === null || _a === void 0 ? void 0 : _a.subject; }) + .filter(x => x !== undefined); + core.setFailed("The PR title's bump level is not consistent with its commits.\n" + + `The PR title type ${prTitle.type} represents bump level ` + + `${semver_1.SemVerType[prTitle.bump]}, while the highest bump in the ` + + `commits is ${semver_1.SemVerType[highestBump]}.\n` + + `PR title: "${prTitleText}"\n` + + `Commit list:\n${` - ${commitSubjects.join("\n - ")}`}`); + return false; + } + else { + core.info(`✅ The pull request title's bump level is consistent with the PR's commits`); + return true; + } } exports.validatePrTitleBump = validatePrTitleBump; @@ -47693,12 +47619,33 @@ module.exports = JSON.parse('[[[0,44],"disallowed_STD3_valid"],[[45,46],"valid"] /******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; /******/ /************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module is referenced by other modules so it can't be inlined -/******/ var __webpack_exports__ = __nccwpck_require__(1144); -/******/ module.exports = __webpack_exports__; -/******/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; +var exports = __webpack_exports__; + +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +const validate_1 = __nccwpck_require__(1144); +(0, validate_1.run)(); + +})(); + +module.exports = __webpack_exports__; /******/ })() ; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1a852c9d..51119c46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,8 +28,8 @@ "@types/difflib": "^0.2.6", "@types/jest": "^29.4.0", "@types/node": "^18.13.0", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.56.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", "@vercel/ncc": "^0.36.1", "eslint": "^8.36.0", "eslint-import-resolver-typescript": "^3.6.1", @@ -39,8 +39,7 @@ "npm-run-all": "^4.1.5", "pkg": "^5.8.0", "prettier": "3.0.0", - "ts-jest": "^29.0.5", - "typescript": "^4.9.5" + "ts-jest": "^29.0.5" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1697,12 +1696,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@pkgr/utils/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2088,32 +2081,90 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", + "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/type-utils": "6.13.2", + "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", + "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", + "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", + "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependenciesMeta": { "typescript": { @@ -2121,26 +2172,244 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", + "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", + "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/parser": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", + "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", + "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", + "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", + "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", + "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/scope-manager": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", + "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/utils": "6.13.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", + "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", + "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", + "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependenciesMeta": { "typescript": { @@ -2148,48 +2417,46 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", + "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", + "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "@typescript-eslint/types": "6.13.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, "node_modules/@typescript-eslint/types": { @@ -3882,210 +4149,6 @@ "eslint": "^8.0.1" } }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", - "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/type-utils": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/parser": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", - "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", - "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/type-utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", - "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", - "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", - "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", - "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-github/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", - "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.13.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-github/node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/eslint-plugin-i18n-text": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-i18n-text/-/eslint-plugin-i18n-text-1.0.1.tgz", @@ -6688,12 +6751,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -8432,12 +8489,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -8644,9 +8695,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/tsutils": { @@ -8664,6 +8715,12 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -8784,16 +8841,17 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { diff --git a/package.json b/package.json index 137530e2..aad8c865 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "scripts": { "build": "run-p build:*", "build:cli": "ncc build -o dist/cli src/cli/cli.ts", - "build:validate": "ncc build -o dist/validate src/actions/validate.ts", - "build:bump": "ncc build -o dist/bump src/actions/bump.ts", + "build:validate": "ncc build -o dist/validate src/actions/entrypoints/validate.ts", + "build:bump": "ncc build -o dist/bump src/actions/entrypoints/bump.ts", "test": "jest", "lint": "eslint **/*.ts --quiet", "format": "prettier --write **/*.ts", @@ -55,8 +55,8 @@ "@types/difflib": "^0.2.6", "@types/jest": "^29.4.0", "@types/node": "^18.13.0", - "@typescript-eslint/eslint-plugin": "^5.55.0", - "@typescript-eslint/parser": "^5.56.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", "@vercel/ncc": "^0.36.1", "eslint": "^8.36.0", "eslint-import-resolver-typescript": "^3.6.1", @@ -66,7 +66,6 @@ "npm-run-all": "^4.1.5", "pkg": "^5.8.0", "prettier": "3.0.0", - "ts-jest": "^29.0.5", - "typescript": "^4.9.5" + "ts-jest": "^29.0.5" } } diff --git a/src/actions/bump.ts b/src/actions/bump.ts index c6a55737..45dc8a3f 100644 --- a/src/actions/bump.ts +++ b/src/actions/bump.ts @@ -18,7 +18,6 @@ import * as core from "@actions/core"; import { context } from "@actions/github"; import { - bumpDraftRelease, bumpSdkVer, bumpSemVer, getVersionBumpTypeAndMessages, @@ -41,8 +40,10 @@ import { * This action: * - takes inputs `config`, `version-prefix`, `create-release` and `create-tag` * - sets outputs `current-version` and `next-version` + * + * @internal */ -async function run(): Promise { +export async function run(): Promise { // Try to download and load configuration await getConfig(core.getInput("config")); const config = new Configuration(".commisery.yml"); @@ -55,7 +56,7 @@ async function run(): Promise { isBranchAllowedToPublish = new RegExp(config.allowedBranches).test( branchName ); - } catch (e) { + } catch (e: unknown) { core.startGroup( "❌ Configuration error - invalid 'allowed-branches' RegEx" ); @@ -168,15 +169,9 @@ async function run(): Promise { `Unimplemented 'version-scheme': ${config.versionScheme}` ); } - } catch (ex) { + } catch (ex: unknown) { core.startGroup("❌ Exception"); core.setFailed((ex as Error).message); core.endGroup(); } } - -run(); - -export const exportedForTesting = { - run, -}; diff --git a/src/actions/entrypoints/bump.ts b/src/actions/entrypoints/bump.ts new file mode 100644 index 00000000..b4cb74ad --- /dev/null +++ b/src/actions/entrypoints/bump.ts @@ -0,0 +1,19 @@ +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { run } from "../bump"; + +run(); diff --git a/src/actions/entrypoints/validate.ts b/src/actions/entrypoints/validate.ts new file mode 100644 index 00000000..c1354a3a --- /dev/null +++ b/src/actions/entrypoints/validate.ts @@ -0,0 +1,19 @@ +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { run } from "../validate"; + +run(); diff --git a/src/actions/validate.ts b/src/actions/validate.ts index c8bd24a1..e792e2c5 100644 --- a/src/actions/validate.ts +++ b/src/actions/validate.ts @@ -51,7 +51,13 @@ async function determineLabels( return labels; } -async function run(): Promise { +/** + * Validate action entrypoint + * + * Validates commits agains the Conventional Commits specification. + * @internal + */ +export async function run(): Promise { try { if (!isPullRequestEvent()) { core.warning( @@ -85,13 +91,7 @@ async function run(): Promise { if (compliant) { core.info("✅ The pull request passed all configured checks"); } - } catch (ex) { + } catch (ex: unknown) { core.setFailed((ex as Error).message); } } - -run(); - -export const exportedForTesting = { - run, -}; diff --git a/src/bump.ts b/src/bump.ts index bb2db862..1c4572e7 100644 --- a/src/bump.ts +++ b/src/bump.ts @@ -80,7 +80,7 @@ function getSemVerIfMatches( commitSha: string ): SemVer | null { if (commitSha === tagSha) { - const dbg = (tag, commit, message): void => { + const dbg = (tag: string, commit: string, message: string): void => { core.debug(`Tag '${tag}' on commit '${commit.slice(0, 6)}' ${message}`); }; const sv: SemVer | null = SemVer.fromString(tagName); @@ -111,9 +111,9 @@ function processCommitsForBump( // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = JSON.parse(JSON.stringify(config)); - configCopy.rules["C014"].enabled = false; // SubjectExceedsLineLengthLimit - configCopy.rules["C019"].enabled = false; // SubjectContainsIssueReference + const configCopy = Object.create(config); + configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference return processCommits(commits, configCopy); } @@ -172,7 +172,7 @@ export async function getVersionBumpTypeAndMessages( core.debug(`Fetching last ${PAGE_SIZE} tags from ${targetSha}..`); const tags = await getLatestTags(PAGE_SIZE); core.debug("Fetch complete"); - const tagMatcher = (commitMessage, commitSha): SemVer | null => { + const tagMatcher = (commitSha: string): SemVer | null => { // Try and match this commit's hash to one of the tags in `tags` for (const tag of tags) { let semVer: SemVer | null = null; @@ -218,7 +218,6 @@ export async function getVersionBumpTypeAndMessages( core.debug(`Commit ${commitSha.slice(0, 6)} is not associated with a tag`); return null; }; - const [version, commitList] = await matchTagsToCommits(targetSha, tagMatcher); const results = processCommitsForBump(commitList, config); @@ -568,7 +567,7 @@ function getNextSdkVer( const currentIsRc = currentVersion.prerelease.startsWith(RC_PREFIX); const currentIsRel = currentVersion.prerelease === ""; - const fatal = (msg): void => { + const fatal = (msg: string): void => { throw new BumpError(msg); }; const bumpOrError = (t: SemVerType): SemVer => { @@ -746,14 +745,14 @@ function getNextSdkVer( export async function bumpSdkVer( config: Configuration, bumpInfo: IVersionBumpTypeAndMessages, - releaseMode, + releaseMode: ReleaseMode, sdkVerBumpType: SdkVerBumpType, - headSha, - branchName, + headSha: string, + branchName: string, isBranchAllowedToPublish: boolean, createChangelog: boolean ): Promise { - const isReleaseBranch = branchName.match(config.releaseBranches); + const isReleaseBranch = branchName.match(config.releaseBranches) !== null; const hasBreakingChange = bumpInfo.processedCommits.some( c => c.message?.breakingChange ); diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 4371d143..0d734230 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -69,12 +69,15 @@ program for (const message of messages) { try { new ConventionalCommitMessage(message, undefined, config); - } catch (error) { + } catch (error: unknown) { if (error instanceof ConventionalCommitError) { for (const err of error.errors) { core.info(err.report()); } + continue; } + + throw error; } } }); @@ -116,11 +119,12 @@ program core.info(os.EOL); for (const rule in config.rules) { - const status: string = config.rules[rule].enabled + const status: string = config.rules.get(rule)?.enabled ? `${green}o${reset}` : `${red}x${reset}`; core.info( - `[${status}] ${rule}: ${gray}${config.rules[rule].description}${reset}` + `[${status}] ${rule}: ${gray}${config.rules.get(rule) + ?.description}${reset}` ); } }); diff --git a/src/cli/utils.ts b/src/cli/utils.ts index 7459bdb7..37baf9a5 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { simpleGit } from "simple-git"; +import { GitError, simpleGit } from "simple-git"; let __ROOT_PATH: string | undefined = undefined; @@ -25,8 +25,12 @@ export async function getRootPath(): Promise { if (__ROOT_PATH === undefined) { try { __ROOT_PATH = await simpleGit().revparse({ "--show-toplevel": null }); - } catch (GitError) { - __ROOT_PATH = process.cwd(); + } catch (error: unknown) { + if (error instanceof GitError) { + __ROOT_PATH = process.cwd(); + } else { + throw error; + } } } @@ -76,8 +80,7 @@ export async function getCommitMessages(target: string[]): Promise { for (const hash of commitHashes) { try { messages.push(await getCommitMessage(hash)); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { + } catch (error: unknown) { continue; } } diff --git a/src/commit.ts b/src/commit.ts index 8bc2bb7e..cfb63d91 100755 --- a/src/commit.ts +++ b/src/commit.ts @@ -249,7 +249,7 @@ function isMerge(subject: string): boolean { return merge !== null; } -function stripMessage(message): string { +function stripMessage(message: string): string { const cutLine = message.indexOf( "# ------------------------ >8 ------------------------\n" ); diff --git a/src/config.ts b/src/config.ts index 4592dfac..5def7936 100644 --- a/src/config.ts +++ b/src/config.ts @@ -18,7 +18,7 @@ import { ALL_RULES } from "./rules"; import { IRuleConfigItem, IConfigurationRules, - IConfiguration, + ITypeTagConfigItem, } from "./interfaces"; import * as core from "@actions/core"; @@ -82,10 +82,8 @@ const VERSION_SCHEMES = ["semver", "sdkver"]; */ function verifyTypeMatches( name: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - typeToTest: any, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - typeItShouldBe: any + typeToTest: unknown, + typeItShouldBe: unknown ): void { if (typeof typeToTest !== typeof typeItShouldBe) { throw new Error( @@ -118,7 +116,19 @@ export class Configuration { return this._initialDevelopment; } - private loadFromData(data: IConfiguration): void { + setRuleActivationStatus(ruleId: string, enabled: boolean): void { + const rule = this.rules.get(ruleId); + if (rule !== undefined) { + rule.enabled = enabled; + } else { + core.warning( + `Rule "${ruleId}" is unknown; enabling or disabling it has no effect.` + ); + } + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private loadFromData(data: any): void { for (const key in data) { if (!CONFIG_ITEMS.includes(key)) { throw new Error(`Unknown configuration item '${key}' detected!`); @@ -136,13 +146,7 @@ export class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - if (item in this.rules) { - this.rules[item].enabled = key === "enable"; - } else { - core.warning( - `Rule "${item}" is unknown; enabling or disabling it has no effect.` - ); - } + this.setRuleActivationStatus(item, key === "enable"); } } else { throw new Error( @@ -188,28 +192,32 @@ export class Configuration { break; case "object": - for (const entry of Object.keys(typeValue)) { - if (["description", "bump"].includes(entry)) { - if (entry === "description") { - verifyTypeMatches( - `${typ}.${entry}`, - typeValue[entry], - "" - ); - } else if (entry === "bump") { - verifyTypeMatches( - `${typ}.${entry}`, - typeValue[entry], - true + { + const tagObject: ITypeTagConfigItem = this.tags[typ] ?? {}; + for (const entry of Object.keys(typeValue)) { + if (["description", "bump"].includes(entry)) { + if (entry === "description") { + verifyTypeMatches( + `${typ}.${entry}`, + typeValue[entry], + "" + ); + tagObject.description = typeValue[entry]; + } else if (entry === "bump") { + verifyTypeMatches( + `${typ}.${entry}`, + typeValue[entry], + true + ); + tagObject.bump = typeValue[entry]; + } + } else { + core.info( + `Warning: "${key}.${typ}.${entry}" is unknown and has no effect.` ); } - this.tags[typ] = this.tags[typ] ? this.tags[typ] : {}; - this.tags[typ][entry] = typeValue[entry]; - } else { - core.info( - `Warning: "${key}.${typ}.${entry}" is unknown and has no effect.` - ); } + this.tags[typ] = tagObject; } break; default: @@ -375,10 +383,10 @@ export class Configuration { */ constructor(configPath: string = DEFAULT_CONFIGURATION_FILE) { for (const rule of ALL_RULES) { - this.rules[rule.id] = { + this.rules.set(rule.id, { description: rule.description, enabled: rule.default, - }; + }); } if (fs.existsSync(configPath)) { const data = yaml.parse(fs.readFileSync(configPath, "utf8")); diff --git a/src/errors.ts b/src/errors.ts index 583fa2e2..91956623 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -41,7 +41,7 @@ export class FixupCommitError extends Error { } export class BumpError extends Error { - constructor(msg) { + constructor(msg: string) { super(`Error while applying version bump: ${msg}`); this.name = "BumpError"; } diff --git a/src/github.ts b/src/github.ts index 28d4a0e4..c691f8c7 100644 --- a/src/github.ts +++ b/src/github.ts @@ -434,13 +434,15 @@ export async function getAssociatedPullRequests( }); return prs; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error.message !== "Resource not accessible by integration") { - throw error; + } catch (error: unknown) { + if ( + error instanceof Error && + error.message === "Resource not accessible by integration" + ) { + return []; } - return []; + throw error; } } @@ -482,15 +484,18 @@ export async function updateLabels(labels: string[]): Promise { labels, }); } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - if (error.message !== "Resource not accessible by integration") { - throw error; + } catch (error: unknown) { + if ( + error instanceof Error && + error.message === "Resource not accessible by integration" + ) { + core.warning( + "Unable to update Pull Request labels, did you provide the `write` permission for `issues` and `pull-requests`?" + ); + return; } - core.warning( - "Unable to update Pull Request labels, did you provide the `write` permission for `issues` and `pull-requests`?" - ); + + throw error; } } @@ -508,8 +513,9 @@ export async function getContent(path: string): Promise { if ("content" in response.data) { return Buffer.from(response.data.content, "base64").toString("utf8"); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { + } catch (error: unknown) { + // We intentially capture all failures and return `undefined` in case the + // file does not exist or cannot be accessed. core.debug((error as Error).message); } } diff --git a/src/interfaces.ts b/src/interfaces.ts index 2784d4a8..9efe7a1f 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -45,13 +45,6 @@ export interface IConfigurationRules { [key: string]: ITypeTagConfigItem; } -export interface IConfiguration { - disable: string[]; - "max-subject-length": number; - tags: IConfigurationRules; - "allowed-branches": string; -} - export interface ISemVer { major: number; minor: number; diff --git a/src/rules.ts b/src/rules.ts index 65240874..3fd20e33 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -40,8 +40,8 @@ export function validateRules( ): LlvmError[] { const errors: LlvmError[] = []; - const disabledRules = Object.entries(config.rules) - .filter(item => !(item[1] as Object)["enabled"]) + const disabledRules = Array.from(config.rules) + .filter(item => item[1].enabled === false) .map(item => item[0]); for (const rule of ALL_RULES) { @@ -49,12 +49,13 @@ export function validateRules( if (!disabledRules.includes(rule.id)) { rule.validate(message, config); } - } catch (error) { + } catch (error: unknown) { if (error instanceof LlvmError) { errors.push(error); - } else { - throw error; + continue; } + + throw error; } } diff --git a/src/semver.ts b/src/semver.ts index 1d45a9cd..fff4f5e7 100644 --- a/src/semver.ts +++ b/src/semver.ts @@ -66,7 +66,7 @@ export class SemVer { this.prefix = prefix; } - static copy(semver): SemVer { + static copy(semver: ISemVer): SemVer { return new SemVer({ build: semver.build, ...semver, diff --git a/src/validate.ts b/src/validate.ts index f72ddd9f..af9d7c54 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -89,7 +89,7 @@ function outputCommitErrors( */ export function outputCommitListErrors( validationResults: IValidationResult[], - useErrorLevel + useErrorLevel: boolean ): void { for (const c of validationResults) { if (c.errors.length > 0) { @@ -114,19 +114,22 @@ export function processCommits( try { const cc = new ConventionalCommitMessage(message, undefined, config); results.push({ input: commit, message: cc, errors: [] }); - } catch (error) { + } catch (error: unknown) { if (error instanceof ConventionalCommitError) { results.push({ input: commit, message: undefined, errors: error.errors, }); + continue; } else if ( error instanceof MergeCommitError || error instanceof FixupCommitError ) { continue; } + + throw error; } } return results; @@ -189,17 +192,20 @@ export async function validatePrTitle( "with the Conventional Commits specification"; try { conventionalCommitMessage = new ConventionalCommitMessage(prTitleText); - } catch (error) { + } catch (error: unknown) { if (error instanceof ConventionalCommitError) { errors = error.errors; - } else { - if (error instanceof MergeCommitError) { - errorMessage = `${errorMessage} (it describes a merge commit)`; - } else if (error instanceof FixupCommitError) { - errorMessage = `${errorMessage} (it describes a fixup commit)`; - } + } else if ( + error instanceof MergeCommitError || + error instanceof FixupCommitError + ) { + errorMessage = `${errorMessage} (it describes a ${ + error instanceof MergeCommitError ? "merge" : "fixup" + } commit)`; core.setFailed(errorMessage); return undefined; + } else { + throw error; } } if (errors.length > 0) { diff --git a/test/bump.sdkver.test.ts b/test/bump.sdkver.test.ts index 04740948..07ecc35b 100644 --- a/test/bump.sdkver.test.ts +++ b/test/bump.sdkver.test.ts @@ -19,7 +19,6 @@ import * as gh from "@actions/github"; import * as github from "../src/github"; import * as bumpaction from "../src/actions/bump"; import * as changelog from "../src/changelog"; -import { Configuration } from "../src/config"; import * as fs from "fs"; import { SemVer } from "../src/semver"; @@ -150,7 +149,7 @@ const testFunction = async (p: SdkBumpTestParameters) => { .spyOn(github, "matchTagsToCommits") .mockResolvedValue([SemVer.fromString(p.initialVersion), messages]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(core.info).toHaveBeenCalledWith( expect.stringContaining(`Found SdkVer tag: ${p.initialVersion}`) ); @@ -352,7 +351,7 @@ describe("Create release branch", () => { gh.context.ref = `refs/heads/${branch}`; setInputSpyWith({ "release-type": bumpType }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); if (branch === "main" && ["rel", "rc"].includes(bumpType)) { expect(github.createBranch).toHaveBeenCalledWith( @@ -367,7 +366,7 @@ describe("Create release branch", () => { it("should be default disabled", async () => { gh.context.ref = "refs/heads/main"; jest.spyOn(fs, "readFileSync").mockReturnValue(`version-scheme: "sdkver"`); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.createBranch).not.toHaveBeenCalled(); }); @@ -378,7 +377,7 @@ describe("Create release branch", () => { .mockReturnValue( `version-scheme: "sdkver"\nsdkver-create-release-branches: true` ); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.createBranch).toHaveBeenCalledWith( "refs/heads/release/1.3", "baaaadb0b" @@ -392,7 +391,7 @@ describe("Create release branch", () => { .mockReturnValue( `version-scheme: "sdkver"\nsdkver-create-release-branches: "rel-"` ); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.createBranch).toHaveBeenCalledWith( "refs/heads/rel-1.3", "baaaadb0b" @@ -431,7 +430,7 @@ describe("Create changelog", () => { }); setInputSpyWith({ "release-type": "rel" }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); if (createChangelog) { expect(changelog.generateChangelog).toHaveBeenCalledTimes(1); expect(github.createRelease).toHaveBeenCalledTimes(1); diff --git a/test/bump.test.ts b/test/bump.test.ts index 0965145d..23b26264 100644 --- a/test/bump.test.ts +++ b/test/bump.test.ts @@ -128,7 +128,7 @@ describe("Bump functionality", () => { messages.concat(U.DEFAULT_COMMIT_LIST), ]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(core.info).toHaveBeenCalledWith( expect.stringContaining(`Found SemVer tag: ${U.INITIAL_VERSION}`) ); @@ -192,7 +192,7 @@ describe("Releases and tags", () => { return false; }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); if (!rel && !tag) { expect(core.startGroup).toHaveBeenCalledWith( expect.stringContaining( @@ -250,7 +250,7 @@ describe("Trouble bumping", () => { jest .spyOn(github, "matchTagsToCommits") .mockResolvedValue([null, [U.PATCH_MSG].concat(U.DEFAULT_COMMIT_LIST)]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(core.warning).toHaveBeenCalledTimes(1); expect(core.warning).toHaveBeenCalledWith( expect.stringContaining("No matching SemVer tags found") @@ -274,7 +274,7 @@ describe("Trouble bumping", () => { ), ]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); // Warning about compliance, as well as what's wrong with the commit(s) expect(core.warning).toHaveBeenCalledWith( expect.stringContaining("not comply") @@ -305,7 +305,7 @@ describe("Trouble bumping", () => { throw new Error("Mocked error"); }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.getShaForTag).toHaveBeenCalledTimes(1); @@ -329,7 +329,7 @@ describe("Trouble bumping", () => { throw new Error("Mocked error"); }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.getShaForTag).toHaveBeenCalledTimes(1); @@ -354,7 +354,7 @@ describe("Trouble bumping", () => { .spyOn(github, "createRelease") .mockRejectedValue(U.getMockRequestError(422)); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(github.getShaForTag).toHaveBeenCalledTimes(1); expect(github.getShaForTag).toHaveBeenCalledWith( @@ -396,7 +396,7 @@ describe("Initial development", () => { [U.toICommit("chore!: breaking change")].concat(U.DEFAULT_COMMIT_LIST), ]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(core.warning).toHaveBeenCalledWith( expect.stringContaining("This repository is under 'initial development'") ); @@ -426,7 +426,7 @@ describe("Initial development", () => { U.DEFAULT_COMMIT_LIST, ]); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); expect(core.warning).toHaveBeenCalledWith( expect.stringContaining("Enforcing version `1.0.0`") ); @@ -481,7 +481,7 @@ describe("Create changelog", () => { return false; }); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); if (createChangelog) { expect(changelog.generateChangelog).toHaveBeenCalledTimes(1); expect(github.createRelease).toHaveBeenCalledTimes(1); diff --git a/test/config.test.ts b/test/config.test.ts index d4a1383c..4dc6447d 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -74,9 +74,9 @@ describe("Configurable options", () => { "C023", "C024", ]; - withConfig("", config => { - const enabledRules = Object.entries(config.rules) - .filter(item => (item[1] as Object)["enabled"]) + withConfig("", (config: Configuration) => { + const enabledRules = Array.from(config.rules) + .filter(item => item[1].enabled) .map(item => item[0]); expect(enabledRules).toEqual(expectedRules); }); @@ -84,9 +84,9 @@ describe("Configurable options", () => { test("Default disabled ruleset", () => { const expectedRules = ["C026"]; - withConfig("", config => { - const disabledRules = Object.entries(config.rules) - .filter(item => !(item[1] as Object)["enabled"]) + withConfig("", (config: Configuration) => { + const disabledRules = Array.from(config.rules) + .filter(item => !item[1].enabled) .map(item => item[0]); expect(disabledRules).toEqual(expectedRules); }); @@ -101,8 +101,8 @@ describe("Configurable options", () => { - C016 `), config => { - expect(config.rules["C003"].enabled).toEqual(false); - expect(config.rules["C016"].enabled).toEqual(false); + expect(config.rules.get("C003").enabled).toEqual(false); + expect(config.rules.get("C016").enabled).toEqual(false); expect(() => { new ConventionalCommitMessage( @@ -117,7 +117,6 @@ describe("Configurable options", () => { test("Disable nonexistent rule", () => { const coreWarning = jest.spyOn(core, "warning").mockImplementation(); - withConfig( dedent(` disable: @@ -125,10 +124,7 @@ describe("Configurable options", () => { - XYZZY0123 - C002 `), - config => { - expect(() => { - new ConventionalCommitMessage("ci: make things", undefined, config); - }).not.toThrow(ConventionalCommitError); + _config => { expect(coreWarning).toHaveBeenCalledTimes(1); } ); @@ -142,7 +138,7 @@ describe("Configurable options", () => { - C026 `), config => { - expect(config.rules["C026"].enabled).toEqual(true); + expect(config.rules.get("C026").enabled).toEqual(true); expect(() => { new ConventionalCommitMessage( @@ -158,7 +154,6 @@ describe("Configurable options", () => { test("Enable nonexistent rule", () => { const coreWarning = jest.spyOn(core, "warning").mockImplementation(); - withConfig( dedent(` enable: @@ -166,7 +161,7 @@ describe("Configurable options", () => { - XYZZY0123 - C002 `), - config => { + _config => { expect(coreWarning).toHaveBeenCalledTimes(1); } ); diff --git a/test/rules.test.ts b/test/rules.test.ts index 87a4a951..6cd7e9f4 100644 --- a/test/rules.test.ts +++ b/test/rules.test.ts @@ -605,7 +605,7 @@ describe("Rules", () => { */ test(`[C026] A ticket reference is required in at least one footer value`, () => { const config = new Configuration(); - config.rules["C026"].enabled = true; + config.setRuleActivationStatus("C026", true); for (const message of [ "test: no footer", diff --git a/test/validate.test.ts b/test/validate.test.ts index f148292c..2851c225 100644 --- a/test/validate.test.ts +++ b/test/validate.test.ts @@ -76,7 +76,7 @@ describe("Valid cases", () => { jest.spyOn(github, "getCommitsInPR").mockResolvedValue(messages); jest.spyOn(github, "getPullRequestTitle").mockResolvedValue(prTitle); - validate.exportedForTesting.run().then(() => { + validate.run().then(() => { expect(core.info).toHaveBeenCalled(); expect(core.warning).not.toHaveBeenCalled(); expect(core.setFailed).not.toHaveBeenCalled(); @@ -108,7 +108,7 @@ describe("Warning cases", () => { jest.spyOn(github, "getCommitsInPR").mockResolvedValue(messages); jest.spyOn(github, "getPullRequestTitle").mockResolvedValue(prTitle); - validate.exportedForTesting.run().then(() => { + validate.run().then(() => { expect(core.warning).toHaveBeenCalled(); for (const msg of warningMessages) { expect(core.warning).toHaveBeenCalledWith( @@ -172,7 +172,7 @@ describe("Error cases", () => { jest.spyOn(github, "getCommitsInPR").mockResolvedValue(messages); jest.spyOn(github, "getPullRequestTitle").mockResolvedValue(prTitle); - validate.exportedForTesting.run().then(() => { + validate.run().then(() => { expect(core.setFailed).toHaveBeenCalled(); for (const msg of failureMessages) { @@ -233,7 +233,7 @@ describe("Update labels", () => { .spyOn(Configuration.prototype, "initialDevelopment", "get") .mockReturnValue(initialDevelopment); - validate.exportedForTesting.run().then(() => { + validate.run().then(() => { expect(core.info).toHaveBeenCalled(); expect(core.setFailed).not.toHaveBeenCalled(); expect(core.warning).not.toHaveBeenCalled(); diff --git a/tsconfig.json b/tsconfig.json index d0d52b2b..a0e994fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,8 +2,6 @@ "compilerOptions": { "target": "ES2019", "module": "commonjs", - "declaration": true, - "outDir": "./lib", "strict": true, "esModuleInterop": true, "stripInternal": true, From 7403705e7258c20054aa910cbbf3c4c461673927 Mon Sep 17 00:00:00 2001 From: Kevin de Jong Date: Thu, 7 Dec 2023 16:21:38 +0100 Subject: [PATCH 4/5] feat: support GitHub cutting-lines in git-trailers This commit introduces support for cutting-lines, as inserted by GitHub in certain merge strategies. In example: ``` feat: remove logout button BREAKING-CHANGE: this removes the logout button as we want all users to be trapped in this application -------- co-authored-by: Bob the Builder ``` This would originally result in only the `co-authored-by` trailer to be accepted, dropping the `BREAKING CHANGE` flag (and therefor only bumping the MINOR version). This change will ignore the cutting-line and consider both elements in the above example as valid trailers. NOTE: the cutting-line is the only exception, any other paragraph entry will still discard previous git-trailers; i.e. ``` feat: remove logout button BREAKING-CHANGE: this removes the logout button as we want all users to be trapped in this application -------- This parapgraph causes the BREAKING-CHANGE to be discarded co-authored-by: Bob the Builder ``` --- dist/bump/index.js | 116 ++++++++++-------- dist/cli/index.js | 108 ++++++++++------- dist/validate/index.js | 118 ++++++++++-------- jest.config.js | 4 +- package-lock.json | 254 --------------------------------------- package.json | 2 - src/actions/validate.ts | 2 +- src/bump.ts | 6 +- src/commit.ts | 72 ++++++----- src/config.ts | 22 +++- src/github.ts | 4 +- src/rules.ts | 22 +--- src/semver.ts | 2 +- test/bump.sdkver.test.ts | 2 +- test/bump.test.ts | 75 +++++++++++- test/commit.test.ts | 39 ++++-- test/config.test.ts | 107 ++++++++++++----- test/rules.test.ts | 37 +----- test/semver.test.ts | 4 + test/test_utils.ts | 10 +- test/validate.test.ts | 2 +- 21 files changed, 466 insertions(+), 542 deletions(-) diff --git a/dist/bump/index.js b/dist/bump/index.js index e719ace6..4eb2c9b6 100644 --- a/dist/bump/index.js +++ b/dist/bump/index.js @@ -33858,9 +33858,9 @@ function processCommitsForBump(commits, config) { // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = Object.create(config); - configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit - configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference + const configCopy = config.copy(); + configCopy.setRuleActive("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActive("C019", false); // SubjectContainsIssueReference return (0, validate_1.processCommits)(commits, configCopy); } /** @@ -34806,20 +34806,36 @@ const semver_1 = __nccwpck_require__(8593); const os = __importStar(__nccwpck_require__(2037)); const BREAKING_CHANGE_TOKEN = "BREAKING-CHANGE"; const CONVENTIONAL_COMMIT_REGEX = /(?\w+)?((\s*)?\((?[^()]*)\)(\s*)?)?(?((\s*)+[!]+(\s*)?)?)(?((\s+)?:?(\s+)?))(?.*)/; -const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=[#]))(?.*)/; +const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=#))(?.*)/; /** * Footer class containing key, value pairs */ class Footer { constructor(token, value) { this.token = token; + this.value = value; + } + set token(token) { if (token === "BREAKING CHANGE") { - this.token = BREAKING_CHANGE_TOKEN; + this._token = BREAKING_CHANGE_TOKEN; } - this.value = value; + else { + this._token = token; + } + } + get token() { + return this._token; + } + set value(value) { + this._value = value; + } + // NOTE: Returns the value of the footer, without + // any trailing whitespace or new line + get value() { + return this._value.trimEnd(); } - appendParagrah(paragrah) { - this.value += os.EOL + paragrah; + appendParagraph(paragraph) { + this._value += os.EOL + paragraph; } } /** @@ -34830,34 +34846,36 @@ function getConventionalCommitMetadata(message) { var _a; let footers = []; let body = []; - let hasBreakingChange = false; if (message.length > 1) { let endOfBody = 1; + let ignoreEmptyLines = false; // eslint-disable-next-line github/array-foreach message.slice(1).forEach((line, index) => { var _a; - const matches = (_a = line.match(FOOTER_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const matches = (_a = FOOTER_REGEX.exec(line)) === null || _a === void 0 ? void 0 : _a.groups; + const currentTrailer = footers[footers.length - 1]; if (matches) { footers.push(new Footer(matches.token, matches.value)); - if (footers[footers.length - 1].token === BREAKING_CHANGE_TOKEN) { - hasBreakingChange = true; - } + ignoreEmptyLines = false; } - else if (footers.length > 0 && line.startsWith(" ")) { - // Multiline trailers use folding - footers[footers.length - 1].appendParagrah(line); + else if (/^-{8,}$/.test(line)) { + // End current trailer when a `---------` line is detected (i.e. as inserted + // by GitHub for certain merge strategies). + ignoreEmptyLines = true; } - else if (hasBreakingChange === true && line.trim() === "") { - // Allow blank lines after BREAKING[- ]CHANGE - if (footers[footers.length - 1].token !== BREAKING_CHANGE_TOKEN) { - footers.push(new Footer("", "")); - } - return; + else if (ignoreEmptyLines && line.trim() === "") { + // Ignore empty lines after `---------` line + // until the next paragraph or footer element is detected. + } + else if (currentTrailer && (/^\s+/.test(line) || line.trim() === "")) { + // Multiline trailers use folding (RFC822), the exception being for empty lines + currentTrailer.appendParagraph(line); } else { // Discard detected git trailers as non-compliant item has been found endOfBody = index + 1; footers = []; + ignoreEmptyLines = false; } }); // Set the body @@ -34868,7 +34886,7 @@ function getConventionalCommitMetadata(message) { body = [message[endOfBody]]; } } - const conventionalSubject = (_a = message[0].match(CONVENTIONAL_COMMIT_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const conventionalSubject = (_a = CONVENTIONAL_COMMIT_REGEX.exec(message[0])) === null || _a === void 0 ? void 0 : _a.groups; if (conventionalSubject === undefined) { throw new Error(`Commit is not compliant to Conventional Commits (non-strict)`); } @@ -34951,13 +34969,11 @@ class ConventionalCommitMessage { exports.ConventionalCommitMessage = ConventionalCommitMessage; function isFixup(subject) { const AUTOSQUASH_REGEX = /^(?:(?:fixup|squash)!\s+)+/; - const autosquash = subject.match(AUTOSQUASH_REGEX); - return autosquash !== null; + return AUTOSQUASH_REGEX.test(subject); } function isMerge(subject) { const MERGE_REGEX = /^Merge.*?:?[\s\t]*?/; - const merge = subject.match(MERGE_REGEX); - return merge !== null; + return MERGE_REGEX.test(subject); } function stripMessage(message) { const cutLine = message.indexOf("# ------------------------ >8 ------------------------\n"); @@ -35093,7 +35109,7 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } - setRuleActivationStatus(ruleId, enabled) { + setRuleActive(ruleId, enabled) { const rule = this.rules.get(ruleId); if (rule !== undefined) { rule.enabled = enabled; @@ -35122,7 +35138,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - this.setRuleActivationStatus(item, key === "enable"); + this.setRuleActive(item, key === "enable"); } } else { @@ -35173,7 +35189,7 @@ class Configuration { } } else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); + core.warning(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } } this.tags[typ] = tagObject; @@ -35329,6 +35345,21 @@ class Configuration { } } } + /** + * Creates a (deep) copy of the Configuration instance + */ + copy() { + const config = new Configuration(); + config.allowedBranches = this.allowedBranches; + config.maxSubjectLength = this.maxSubjectLength; + config.releaseBranches = this.releaseBranches; + config.versionScheme = this.versionScheme; + config.prereleasePrefix = this.prereleasePrefix; + config.tags = JSON.parse(JSON.stringify(this.tags)); + config.rules = new Map(JSON.parse(JSON.stringify(Array.from(this.rules)))); + config.sdkverCreateReleaseBranches = this.sdkverCreateReleaseBranches; + return config; + } } exports.Configuration = Configuration; /* Exports for tests only */ @@ -35671,7 +35702,7 @@ async function matchTagsToCommits(sha, matcher) { sha, })) { for (const commit of resp.data) { - match = matcher(commit.commit.message, commit.sha); + match = matcher(commit.sha); if (match) { core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); return [match, commitList]; @@ -36613,24 +36644,12 @@ class GitTrailerContainsWhitespace { } } /** - * Footer should not contain any blank line(s) + * Rule C022 was historically known as: + * FooterContainsBlankLine + * with description: + * "Footer should not contain any blank line(s)"; + * This rule has been removed and its ID should therefore not be re-used. */ -class FooterContainsBlankLine { - constructor() { - this.id = "C022"; - this.description = "Footer should not contain any blank line(s)"; - this.default = true; - } - validate(message, _) { - for (const item of message.footers) { - if (!item.token || item.value.length === 0) { - throw new logging_1.LlvmError({ - message: `[${this.id}] ${this.description}`, - }); - } - } - } -} /** * The BREAKING CHANGE git-trailer should be the first element in the footer */ @@ -36749,7 +36768,6 @@ exports.ALL_RULES = [ new MissingEmptyLineBetweenSubjectAndBody(), new SubjectContainsIssueReference(), new GitTrailerContainsWhitespace(), - new FooterContainsBlankLine(), new BreakingChangeMustBeFirstGitTrailer(), new GitTrailerNeedAColon(), new FooterContainsTicketReference(), diff --git a/dist/cli/index.js b/dist/cli/index.js index 5504d10e..22fae4ab 100755 --- a/dist/cli/index.js +++ b/dist/cli/index.js @@ -32540,20 +32540,36 @@ const semver_1 = __nccwpck_require__(8593); const os = __importStar(__nccwpck_require__(2037)); const BREAKING_CHANGE_TOKEN = "BREAKING-CHANGE"; const CONVENTIONAL_COMMIT_REGEX = /(?\w+)?((\s*)?\((?[^()]*)\)(\s*)?)?(?((\s*)+[!]+(\s*)?)?)(?((\s+)?:?(\s+)?))(?.*)/; -const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=[#]))(?.*)/; +const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=#))(?.*)/; /** * Footer class containing key, value pairs */ class Footer { constructor(token, value) { this.token = token; + this.value = value; + } + set token(token) { if (token === "BREAKING CHANGE") { - this.token = BREAKING_CHANGE_TOKEN; + this._token = BREAKING_CHANGE_TOKEN; } - this.value = value; + else { + this._token = token; + } + } + get token() { + return this._token; + } + set value(value) { + this._value = value; + } + // NOTE: Returns the value of the footer, without + // any trailing whitespace or new line + get value() { + return this._value.trimEnd(); } - appendParagrah(paragrah) { - this.value += os.EOL + paragrah; + appendParagraph(paragraph) { + this._value += os.EOL + paragraph; } } /** @@ -32564,34 +32580,36 @@ function getConventionalCommitMetadata(message) { var _a; let footers = []; let body = []; - let hasBreakingChange = false; if (message.length > 1) { let endOfBody = 1; + let ignoreEmptyLines = false; // eslint-disable-next-line github/array-foreach message.slice(1).forEach((line, index) => { var _a; - const matches = (_a = line.match(FOOTER_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const matches = (_a = FOOTER_REGEX.exec(line)) === null || _a === void 0 ? void 0 : _a.groups; + const currentTrailer = footers[footers.length - 1]; if (matches) { footers.push(new Footer(matches.token, matches.value)); - if (footers[footers.length - 1].token === BREAKING_CHANGE_TOKEN) { - hasBreakingChange = true; - } + ignoreEmptyLines = false; } - else if (footers.length > 0 && line.startsWith(" ")) { - // Multiline trailers use folding - footers[footers.length - 1].appendParagrah(line); + else if (/^-{8,}$/.test(line)) { + // End current trailer when a `---------` line is detected (i.e. as inserted + // by GitHub for certain merge strategies). + ignoreEmptyLines = true; } - else if (hasBreakingChange === true && line.trim() === "") { - // Allow blank lines after BREAKING[- ]CHANGE - if (footers[footers.length - 1].token !== BREAKING_CHANGE_TOKEN) { - footers.push(new Footer("", "")); - } - return; + else if (ignoreEmptyLines && line.trim() === "") { + // Ignore empty lines after `---------` line + // until the next paragraph or footer element is detected. + } + else if (currentTrailer && (/^\s+/.test(line) || line.trim() === "")) { + // Multiline trailers use folding (RFC822), the exception being for empty lines + currentTrailer.appendParagraph(line); } else { // Discard detected git trailers as non-compliant item has been found endOfBody = index + 1; footers = []; + ignoreEmptyLines = false; } }); // Set the body @@ -32602,7 +32620,7 @@ function getConventionalCommitMetadata(message) { body = [message[endOfBody]]; } } - const conventionalSubject = (_a = message[0].match(CONVENTIONAL_COMMIT_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const conventionalSubject = (_a = CONVENTIONAL_COMMIT_REGEX.exec(message[0])) === null || _a === void 0 ? void 0 : _a.groups; if (conventionalSubject === undefined) { throw new Error(`Commit is not compliant to Conventional Commits (non-strict)`); } @@ -32685,13 +32703,11 @@ class ConventionalCommitMessage { exports.ConventionalCommitMessage = ConventionalCommitMessage; function isFixup(subject) { const AUTOSQUASH_REGEX = /^(?:(?:fixup|squash)!\s+)+/; - const autosquash = subject.match(AUTOSQUASH_REGEX); - return autosquash !== null; + return AUTOSQUASH_REGEX.test(subject); } function isMerge(subject) { const MERGE_REGEX = /^Merge.*?:?[\s\t]*?/; - const merge = subject.match(MERGE_REGEX); - return merge !== null; + return MERGE_REGEX.test(subject); } function stripMessage(message) { const cutLine = message.indexOf("# ------------------------ >8 ------------------------\n"); @@ -32827,7 +32843,7 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } - setRuleActivationStatus(ruleId, enabled) { + setRuleActive(ruleId, enabled) { const rule = this.rules.get(ruleId); if (rule !== undefined) { rule.enabled = enabled; @@ -32856,7 +32872,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - this.setRuleActivationStatus(item, key === "enable"); + this.setRuleActive(item, key === "enable"); } } else { @@ -32907,7 +32923,7 @@ class Configuration { } } else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); + core.warning(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } } this.tags[typ] = tagObject; @@ -33063,6 +33079,21 @@ class Configuration { } } } + /** + * Creates a (deep) copy of the Configuration instance + */ + copy() { + const config = new Configuration(); + config.allowedBranches = this.allowedBranches; + config.maxSubjectLength = this.maxSubjectLength; + config.releaseBranches = this.releaseBranches; + config.versionScheme = this.versionScheme; + config.prereleasePrefix = this.prereleasePrefix; + config.tags = JSON.parse(JSON.stringify(this.tags)); + config.rules = new Map(JSON.parse(JSON.stringify(Array.from(this.rules)))); + config.sdkverCreateReleaseBranches = this.sdkverCreateReleaseBranches; + return config; + } } exports.Configuration = Configuration; /* Exports for tests only */ @@ -33824,24 +33855,12 @@ class GitTrailerContainsWhitespace { } } /** - * Footer should not contain any blank line(s) + * Rule C022 was historically known as: + * FooterContainsBlankLine + * with description: + * "Footer should not contain any blank line(s)"; + * This rule has been removed and its ID should therefore not be re-used. */ -class FooterContainsBlankLine { - constructor() { - this.id = "C022"; - this.description = "Footer should not contain any blank line(s)"; - this.default = true; - } - validate(message, _) { - for (const item of message.footers) { - if (!item.token || item.value.length === 0) { - throw new logging_1.LlvmError({ - message: `[${this.id}] ${this.description}`, - }); - } - } - } -} /** * The BREAKING CHANGE git-trailer should be the first element in the footer */ @@ -33960,7 +33979,6 @@ exports.ALL_RULES = [ new MissingEmptyLineBetweenSubjectAndBody(), new SubjectContainsIssueReference(), new GitTrailerContainsWhitespace(), - new FooterContainsBlankLine(), new BreakingChangeMustBeFirstGitTrailer(), new GitTrailerNeedAColon(), new FooterContainsTicketReference(), diff --git a/dist/validate/index.js b/dist/validate/index.js index 84fe78f9..8de8c90d 100644 --- a/dist/validate/index.js +++ b/dist/validate/index.js @@ -33668,7 +33668,7 @@ async function determineLabels(conventionalCommits, config) { /** * Validate action entrypoint * - * Validates commits agains the Conventional Commits specification. + * Validates commits against the Conventional Commits specification. * @internal */ async function run() { @@ -33816,9 +33816,9 @@ function processCommitsForBump(commits, config) { // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = Object.create(config); - configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit - configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference + const configCopy = config.copy(); + configCopy.setRuleActive("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActive("C019", false); // SubjectContainsIssueReference return (0, validate_1.processCommits)(commits, configCopy); } /** @@ -34764,20 +34764,36 @@ const semver_1 = __nccwpck_require__(8593); const os = __importStar(__nccwpck_require__(2037)); const BREAKING_CHANGE_TOKEN = "BREAKING-CHANGE"; const CONVENTIONAL_COMMIT_REGEX = /(?\w+)?((\s*)?\((?[^()]*)\)(\s*)?)?(?((\s*)+[!]+(\s*)?)?)(?((\s+)?:?(\s+)?))(?.*)/; -const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=[#]))(?.*)/; +const FOOTER_REGEX = /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=#))(?.*)/; /** * Footer class containing key, value pairs */ class Footer { constructor(token, value) { this.token = token; + this.value = value; + } + set token(token) { if (token === "BREAKING CHANGE") { - this.token = BREAKING_CHANGE_TOKEN; + this._token = BREAKING_CHANGE_TOKEN; } - this.value = value; + else { + this._token = token; + } + } + get token() { + return this._token; + } + set value(value) { + this._value = value; + } + // NOTE: Returns the value of the footer, without + // any trailing whitespace or new line + get value() { + return this._value.trimEnd(); } - appendParagrah(paragrah) { - this.value += os.EOL + paragrah; + appendParagraph(paragraph) { + this._value += os.EOL + paragraph; } } /** @@ -34788,34 +34804,36 @@ function getConventionalCommitMetadata(message) { var _a; let footers = []; let body = []; - let hasBreakingChange = false; if (message.length > 1) { let endOfBody = 1; + let ignoreEmptyLines = false; // eslint-disable-next-line github/array-foreach message.slice(1).forEach((line, index) => { var _a; - const matches = (_a = line.match(FOOTER_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const matches = (_a = FOOTER_REGEX.exec(line)) === null || _a === void 0 ? void 0 : _a.groups; + const currentTrailer = footers[footers.length - 1]; if (matches) { footers.push(new Footer(matches.token, matches.value)); - if (footers[footers.length - 1].token === BREAKING_CHANGE_TOKEN) { - hasBreakingChange = true; - } + ignoreEmptyLines = false; } - else if (footers.length > 0 && line.startsWith(" ")) { - // Multiline trailers use folding - footers[footers.length - 1].appendParagrah(line); + else if (/^-{8,}$/.test(line)) { + // End current trailer when a `---------` line is detected (i.e. as inserted + // by GitHub for certain merge strategies). + ignoreEmptyLines = true; } - else if (hasBreakingChange === true && line.trim() === "") { - // Allow blank lines after BREAKING[- ]CHANGE - if (footers[footers.length - 1].token !== BREAKING_CHANGE_TOKEN) { - footers.push(new Footer("", "")); - } - return; + else if (ignoreEmptyLines && line.trim() === "") { + // Ignore empty lines after `---------` line + // until the next paragraph or footer element is detected. + } + else if (currentTrailer && (/^\s+/.test(line) || line.trim() === "")) { + // Multiline trailers use folding (RFC822), the exception being for empty lines + currentTrailer.appendParagraph(line); } else { // Discard detected git trailers as non-compliant item has been found endOfBody = index + 1; footers = []; + ignoreEmptyLines = false; } }); // Set the body @@ -34826,7 +34844,7 @@ function getConventionalCommitMetadata(message) { body = [message[endOfBody]]; } } - const conventionalSubject = (_a = message[0].match(CONVENTIONAL_COMMIT_REGEX)) === null || _a === void 0 ? void 0 : _a.groups; + const conventionalSubject = (_a = CONVENTIONAL_COMMIT_REGEX.exec(message[0])) === null || _a === void 0 ? void 0 : _a.groups; if (conventionalSubject === undefined) { throw new Error(`Commit is not compliant to Conventional Commits (non-strict)`); } @@ -34909,13 +34927,11 @@ class ConventionalCommitMessage { exports.ConventionalCommitMessage = ConventionalCommitMessage; function isFixup(subject) { const AUTOSQUASH_REGEX = /^(?:(?:fixup|squash)!\s+)+/; - const autosquash = subject.match(AUTOSQUASH_REGEX); - return autosquash !== null; + return AUTOSQUASH_REGEX.test(subject); } function isMerge(subject) { const MERGE_REGEX = /^Merge.*?:?[\s\t]*?/; - const merge = subject.match(MERGE_REGEX); - return merge !== null; + return MERGE_REGEX.test(subject); } function stripMessage(message) { const cutLine = message.indexOf("# ------------------------ >8 ------------------------\n"); @@ -35051,7 +35067,7 @@ class Configuration { get initialDevelopment() { return this._initialDevelopment; } - setRuleActivationStatus(ruleId, enabled) { + setRuleActive(ruleId, enabled) { const rule = this.rules.get(ruleId); if (rule !== undefined) { rule.enabled = enabled; @@ -35080,7 +35096,7 @@ class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - this.setRuleActivationStatus(item, key === "enable"); + this.setRuleActive(item, key === "enable"); } } else { @@ -35131,7 +35147,7 @@ class Configuration { } } else { - core.info(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); + core.warning(`Warning: "${key}.${typ}.${entry}" is unknown and has no effect.`); } } this.tags[typ] = tagObject; @@ -35287,6 +35303,21 @@ class Configuration { } } } + /** + * Creates a (deep) copy of the Configuration instance + */ + copy() { + const config = new Configuration(); + config.allowedBranches = this.allowedBranches; + config.maxSubjectLength = this.maxSubjectLength; + config.releaseBranches = this.releaseBranches; + config.versionScheme = this.versionScheme; + config.prereleasePrefix = this.prereleasePrefix; + config.tags = JSON.parse(JSON.stringify(this.tags)); + config.rules = new Map(JSON.parse(JSON.stringify(Array.from(this.rules)))); + config.sdkverCreateReleaseBranches = this.sdkverCreateReleaseBranches; + return config; + } } exports.Configuration = Configuration; /* Exports for tests only */ @@ -35629,7 +35660,7 @@ async function matchTagsToCommits(sha, matcher) { sha, })) { for (const commit of resp.data) { - match = matcher(commit.commit.message, commit.sha); + match = matcher(commit.sha); if (match) { core.debug(`Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}`); return [match, commitList]; @@ -36571,24 +36602,12 @@ class GitTrailerContainsWhitespace { } } /** - * Footer should not contain any blank line(s) + * Rule C022 was historically known as: + * FooterContainsBlankLine + * with description: + * "Footer should not contain any blank line(s)"; + * This rule has been removed and its ID should therefore not be re-used. */ -class FooterContainsBlankLine { - constructor() { - this.id = "C022"; - this.description = "Footer should not contain any blank line(s)"; - this.default = true; - } - validate(message, _) { - for (const item of message.footers) { - if (!item.token || item.value.length === 0) { - throw new logging_1.LlvmError({ - message: `[${this.id}] ${this.description}`, - }); - } - } - } -} /** * The BREAKING CHANGE git-trailer should be the first element in the footer */ @@ -36707,7 +36726,6 @@ exports.ALL_RULES = [ new MissingEmptyLineBetweenSubjectAndBody(), new SubjectContainsIssueReference(), new GitTrailerContainsWhitespace(), - new FooterContainsBlankLine(), new BreakingChangeMustBeFirstGitTrailer(), new GitTrailerNeedAColon(), new FooterContainsTicketReference(), diff --git a/jest.config.js b/jest.config.js index 42bdeedf..ee779477 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ module.exports = { - transform: { "^.+\\.(t|j)sx?$": "@swc/jest" }, + transform: { "^.+\\.(t|j)sx?$": "ts-jest" }, testEnvironment: "node", testRegex: "/test/.*\\.(test|spec)?\\.(ts|tsx)$", - moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"] }; diff --git a/package-lock.json b/package-lock.json index 51119c46..ce690687 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,8 +22,6 @@ }, "devDependencies": { "@octokit/plugin-rest-endpoint-methods": "^6.7.0", - "@swc/core": "^1.3.36", - "@swc/jest": "^0.2.24", "@types/dedent": "^0.7.0", "@types/difflib": "^0.2.6", "@types/jest": "^29.4.0", @@ -1167,43 +1165,6 @@ } } }, - "node_modules/@jest/create-cache-key-function": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", - "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { - "version": "16.0.9", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", - "integrity": "sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -1722,215 +1683,6 @@ "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@swc/core": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.100.tgz", - "integrity": "sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@swc/counter": "^0.1.1", - "@swc/types": "^0.1.5" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.100", - "@swc/core-darwin-x64": "1.3.100", - "@swc/core-linux-arm64-gnu": "1.3.100", - "@swc/core-linux-arm64-musl": "1.3.100", - "@swc/core-linux-x64-gnu": "1.3.100", - "@swc/core-linux-x64-musl": "1.3.100", - "@swc/core-win32-arm64-msvc": "1.3.100", - "@swc/core-win32-ia32-msvc": "1.3.100", - "@swc/core-win32-x64-msvc": "1.3.100" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz", - "integrity": "sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz", - "integrity": "sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz", - "integrity": "sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz", - "integrity": "sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz", - "integrity": "sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz", - "integrity": "sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz", - "integrity": "sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz", - "integrity": "sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.100", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz", - "integrity": "sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", - "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", - "dev": true - }, - "node_modules/@swc/jest": { - "version": "0.2.29", - "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.29.tgz", - "integrity": "sha512-8reh5RvHBsSikDC3WGCd5ZTd2BXKkyOdK7QwynrCH58jk2cQFhhHhFBg/jvnWZehUQe/EoOImLENc9/DwbBFow==", - "dev": true, - "dependencies": { - "@jest/create-cache-key-function": "^27.4.2", - "jsonc-parser": "^3.2.0" - }, - "engines": { - "npm": ">= 7.0.0" - }, - "peerDependencies": { - "@swc/core": "*" - } - }, - "node_modules/@swc/types": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", - "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", - "dev": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -6381,12 +6133,6 @@ "node": ">=6" } }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", diff --git a/package.json b/package.json index aad8c865..465b6b08 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,6 @@ }, "devDependencies": { "@octokit/plugin-rest-endpoint-methods": "^6.7.0", - "@swc/core": "^1.3.36", - "@swc/jest": "^0.2.24", "@types/dedent": "^0.7.0", "@types/difflib": "^0.2.6", "@types/jest": "^29.4.0", diff --git a/src/actions/validate.ts b/src/actions/validate.ts index e792e2c5..df732938 100644 --- a/src/actions/validate.ts +++ b/src/actions/validate.ts @@ -54,7 +54,7 @@ async function determineLabels( /** * Validate action entrypoint * - * Validates commits agains the Conventional Commits specification. + * Validates commits against the Conventional Commits specification. * @internal */ export async function run(): Promise { diff --git a/src/bump.ts b/src/bump.ts index 1c4572e7..3eac337f 100644 --- a/src/bump.ts +++ b/src/bump.ts @@ -111,9 +111,9 @@ function processCommitsForBump( // commits/pull request titles that (ideally) have been validated // _before_ they were merged, and certain GitHub CI settings may append // a reference to the PR number in merge commits. - const configCopy = Object.create(config); - configCopy.setRuleActivationStatus("C014", false); // SubjectExceedsLineLengthLimit - configCopy.setRuleActivationStatus("C019", false); // SubjectContainsIssueReference + const configCopy = config.copy(); + configCopy.setRuleActive("C014", false); // SubjectExceedsLineLengthLimit + configCopy.setRuleActive("C019", false); // SubjectContainsIssueReference return processCommits(commits, configCopy); } diff --git a/src/commit.ts b/src/commit.ts index cfb63d91..c5efe7e6 100755 --- a/src/commit.ts +++ b/src/commit.ts @@ -29,7 +29,7 @@ const BREAKING_CHANGE_TOKEN = "BREAKING-CHANGE"; const CONVENTIONAL_COMMIT_REGEX = /(?\w+)?((\s*)?\((?[^()]*)\)(\s*)?)?(?((\s*)+[!]+(\s*)?)?)(?((\s+)?:?(\s+)?))(?.*)/; const FOOTER_REGEX = - /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=[#]))(?.*)/; + /^(?[\w-]+|BREAKING\sCHANGE|[\w-\s]+\sby)(?::[ ]|[ ](?=#))(?.*)/; /** * Conventional Commit Metadata used for validating @@ -50,20 +50,38 @@ export interface ConventionalCommitMetadata { * Footer class containing key, value pairs */ class Footer { - token: string; - value: string; + private _token!: string; + private _value!: string; constructor(token: string, value: string) { this.token = token; + this.value = value; + } + + set token(token: string) { if (token === "BREAKING CHANGE") { - this.token = BREAKING_CHANGE_TOKEN; + this._token = BREAKING_CHANGE_TOKEN; + } else { + this._token = token; } + } - this.value = value; + get token(): string { + return this._token; } - appendParagrah(paragrah: string): void { - this.value += os.EOL + paragrah; + set value(value: string) { + this._value = value; + } + + // NOTE: Returns the value of the footer, without + // any trailing whitespace or new line + get value(): string { + return this._value.trimEnd(); + } + + appendParagraph(paragraph: string): void { + this._value += os.EOL + paragraph; } } @@ -76,31 +94,33 @@ export function getConventionalCommitMetadata( ): ConventionalCommitMetadata { let footers: Footer[] = []; let body: string[] = []; - let hasBreakingChange = false; if (message.length > 1) { let endOfBody = 1; + let ignoreEmptyLines = false; + // eslint-disable-next-line github/array-foreach message.slice(1).forEach((line, index) => { - const matches = line.match(FOOTER_REGEX)?.groups; + const matches = FOOTER_REGEX.exec(line)?.groups; + const currentTrailer = footers[footers.length - 1]; if (matches) { footers.push(new Footer(matches.token, matches.value)); - if (footers[footers.length - 1].token === BREAKING_CHANGE_TOKEN) { - hasBreakingChange = true; - } - } else if (footers.length > 0 && line.startsWith(" ")) { - // Multiline trailers use folding - footers[footers.length - 1].appendParagrah(line); - } else if (hasBreakingChange === true && line.trim() === "") { - // Allow blank lines after BREAKING[- ]CHANGE - if (footers[footers.length - 1].token !== BREAKING_CHANGE_TOKEN) { - footers.push(new Footer("", "")); - } - return; + ignoreEmptyLines = false; + } else if (/^-{8,}$/.test(line)) { + // End current trailer when a `---------` line is detected (i.e. as inserted + // by GitHub for certain merge strategies). + ignoreEmptyLines = true; + } else if (ignoreEmptyLines && line.trim() === "") { + // Ignore empty lines after `---------` line + // until the next paragraph or footer element is detected. + } else if (currentTrailer && (/^\s+/.test(line) || line.trim() === "")) { + // Multiline trailers use folding (RFC822), the exception being for empty lines + currentTrailer.appendParagraph(line); } else { // Discard detected git trailers as non-compliant item has been found endOfBody = index + 1; footers = []; + ignoreEmptyLines = false; } }); @@ -112,7 +132,7 @@ export function getConventionalCommitMetadata( } } - const conventionalSubject = message[0].match(CONVENTIONAL_COMMIT_REGEX) + const conventionalSubject = CONVENTIONAL_COMMIT_REGEX.exec(message[0]) ?.groups; if (conventionalSubject === undefined) { @@ -237,16 +257,12 @@ export class ConventionalCommitMessage { function isFixup(subject: string): boolean { const AUTOSQUASH_REGEX = /^(?:(?:fixup|squash)!\s+)+/; - const autosquash = subject.match(AUTOSQUASH_REGEX); - - return autosquash !== null; + return AUTOSQUASH_REGEX.test(subject); } function isMerge(subject: string): boolean { const MERGE_REGEX = /^Merge.*?:?[\s\t]*?/; - const merge = subject.match(MERGE_REGEX); - - return merge !== null; + return MERGE_REGEX.test(subject); } function stripMessage(message: string): string { diff --git a/src/config.ts b/src/config.ts index 5def7936..54b53570 100644 --- a/src/config.ts +++ b/src/config.ts @@ -116,7 +116,7 @@ export class Configuration { return this._initialDevelopment; } - setRuleActivationStatus(ruleId: string, enabled: boolean): void { + setRuleActive(ruleId: string, enabled: boolean): void { const rule = this.rules.get(ruleId); if (rule !== undefined) { rule.enabled = enabled; @@ -146,7 +146,7 @@ export class Configuration { */ if (typeof data[key] === "object") { for (const item of data[key]) { - this.setRuleActivationStatus(item, key === "enable"); + this.setRuleActive(item, key === "enable"); } } else { throw new Error( @@ -212,7 +212,7 @@ export class Configuration { tagObject.bump = typeValue[entry]; } } else { - core.info( + core.warning( `Warning: "${key}.${typ}.${entry}" is unknown and has no effect.` ); } @@ -397,6 +397,22 @@ export class Configuration { } } } + + /** + * Creates a (deep) copy of the Configuration instance + */ + copy(): Configuration { + const config = new Configuration(); + config.allowedBranches = this.allowedBranches; + config.maxSubjectLength = this.maxSubjectLength; + config.releaseBranches = this.releaseBranches; + config.versionScheme = this.versionScheme; + config.prereleasePrefix = this.prereleasePrefix; + config.tags = JSON.parse(JSON.stringify(this.tags)); + config.rules = new Map(JSON.parse(JSON.stringify(Array.from(this.rules)))); + config.sdkverCreateReleaseBranches = this.sdkverCreateReleaseBranches; + return config; + } } /* Exports for tests only */ diff --git a/src/github.ts b/src/github.ts index c691f8c7..72cce890 100644 --- a/src/github.ts +++ b/src/github.ts @@ -297,7 +297,7 @@ export async function getReleaseConfiguration(): Promise { */ export async function matchTagsToCommits( sha: string | undefined, - matcher: (msg: string, hash: string) => SemVer | null + matcher: (hash: string) => SemVer | null ): Promise<[SemVer | null, ICommit[]]> { const octo = getOctokit(); const commitList: ICommit[] = []; @@ -308,7 +308,7 @@ export async function matchTagsToCommits( sha, })) { for (const commit of resp.data) { - match = matcher(commit.commit.message, commit.sha); + match = matcher(commit.sha); if (match) { core.debug( `Matching on (${commit.sha}):${commit.commit.message.split("\n")[0]}` diff --git a/src/rules.ts b/src/rules.ts index 3fd20e33..e9d8276d 100644 --- a/src/rules.ts +++ b/src/rules.ts @@ -589,23 +589,12 @@ class GitTrailerContainsWhitespace implements IConventionalCommitRule { } /** - * Footer should not contain any blank line(s) + * Rule C022 was historically known as: + * FooterContainsBlankLine + * with description: + * "Footer should not contain any blank line(s)"; + * This rule has been removed and its ID should therefore not be re-used. */ -class FooterContainsBlankLine implements IConventionalCommitRule { - id = "C022"; - description = "Footer should not contain any blank line(s)"; - default = true; - - validate(message: ConventionalCommitMetadata, _: Configuration): void { - for (const item of message.footers) { - if (!item.token || item.value.length === 0) { - throw new LlvmError({ - message: `[${this.id}] ${this.description}`, - }); - } - } - } -} /** * The BREAKING CHANGE git-trailer should be the first element in the footer @@ -728,7 +717,6 @@ export const ALL_RULES = [ new MissingEmptyLineBetweenSubjectAndBody(), new SubjectContainsIssueReference(), new GitTrailerContainsWhitespace(), - new FooterContainsBlankLine(), new BreakingChangeMustBeFirstGitTrailer(), new GitTrailerNeedAColon(), new FooterContainsTicketReference(), diff --git a/src/semver.ts b/src/semver.ts index fff4f5e7..1b811f8d 100644 --- a/src/semver.ts +++ b/src/semver.ts @@ -42,7 +42,7 @@ export enum SemVerType { MAJOR = 3, } -export class SemVer { +export class SemVer implements ISemVer { major: number; minor: number; patch: number; diff --git a/test/bump.sdkver.test.ts b/test/bump.sdkver.test.ts index 07ecc35b..ba37e7c1 100644 --- a/test/bump.sdkver.test.ts +++ b/test/bump.sdkver.test.ts @@ -106,7 +106,7 @@ interface SdkBumpTestParameters { breaking: boolean; expectedVersion: string; } -const generateTests = (paramListList): SdkBumpTestParameters[] => { +const generateTests = (paramListList: any): SdkBumpTestParameters[] => { let testList = new Array() as SdkBumpTestParameters[]; for (const paramList of paramListList) { testList.push({ diff --git a/test/bump.test.ts b/test/bump.test.ts index 23b26264..5ae8e218 100644 --- a/test/bump.test.ts +++ b/test/bump.test.ts @@ -19,10 +19,16 @@ import * as gh from "@actions/github"; import * as github from "../src/github"; import * as bumpaction from "../src/actions/bump"; import * as changelog from "../src/changelog"; +import * as validate from "../src/validate"; +import { getVersionBumpTypeAndMessages } from "../src/bump"; import * as fs from "fs"; import { SemVer } from "../src/semver"; import * as U from "./test_utils"; +import { Configuration } from "../src/config"; +import { IGitTag } from "../src/interfaces"; +import { BASE_COMMIT } from "./test_utils"; +import { ALL_RULES } from "../src/rules"; jest.mock("fs", () => ({ promises: { access: jest.fn() }, @@ -39,7 +45,6 @@ jest.mock("../src/changelog"); gh.context = { ref: "refs/heads/main", sha: U.HEAD_SHA }; beforeEach(() => { - jest.resetAllMocks(); jest.spyOn(github, "isPullRequestEvent").mockReturnValue(false); jest.spyOn(github, "createTag").mockResolvedValue(); jest.spyOn(github, "createRelease").mockResolvedValue(); @@ -76,6 +81,10 @@ beforeEach(() => { */ }); +afterEach(() => { + jest.resetAllMocks(); +}); + describe("Bump functionality", () => { const bumpTests = [ { @@ -240,6 +249,10 @@ describe("Trouble bumping", () => { ]); }); + afterEach(() => { + jest.resetAllMocks(); + }); + test("no matching tags found", async () => { jest.spyOn(github, "getLatestTags").mockResolvedValue([ { @@ -577,7 +590,7 @@ describe("Version prefix handling", () => { : "") ); - await bumpaction.exportedForTesting.run(); + await bumpaction.run(); const commitSha = TEST_VERSIONS.find(version => version.name == expected?.toString()) @@ -585,8 +598,62 @@ describe("Version prefix handling", () => { // We specifically test the matcher function passed to matchTagsToCommits here, // as it's (sadly) the only way to test the actual behavior of the matcher. - const matcherFunc = github.matchTagsToCommits.mock.calls[0][1]; - expect(matcherFunc("", commitSha)).toEqual(expected); + const matcherFunc = (github.matchTagsToCommits as jest.Mock).mock + .calls[0][1]; + expect(matcherFunc(commitSha)).toEqual(expected); } ); }); + +describe("Process Commits Configuration", () => { + beforeEach(() => { + jest.spyOn(github, "getLatestTags").mockResolvedValue([ + { + name: "1.0.0", + commitSha: BASE_COMMIT.sha, + }, + ] as IGitTag[]); + + jest + .spyOn(github, "matchTagsToCommits") + .mockResolvedValue([SemVer.fromString("1.0.0"), [BASE_COMMIT]]); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + test("Disable C014 and C019 during bump", async () => { + const processCommits = jest.spyOn(validate, "processCommits"); + + const config = new Configuration(); + await getVersionBumpTypeAndMessages("f00dcafe", config); + + // Both C014 and C019 are disabled when running bump + const expectedConfig = new Configuration(); + expectedConfig.setRuleActive("C014", false); + expectedConfig.setRuleActive("C019", false); + + expect(processCommits).toHaveBeenCalledWith([BASE_COMMIT], expectedConfig); + expect(config).toStrictEqual(new Configuration()); + + processCommits.mockRestore(); + }); + + test("All rules already disabled", async () => { + const processCommits = jest.spyOn(validate, "processCommits"); + + const config = new Configuration(); + ALL_RULES.forEach(rule => config.setRuleActive(rule.id, false)); + + await getVersionBumpTypeAndMessages("f00dcafe", config); + + const expectedConfig = new Configuration(); + ALL_RULES.forEach(rule => expectedConfig.setRuleActive(rule.id, false)); + + expect(processCommits).toHaveBeenCalledWith([BASE_COMMIT], config); + expect(config).toStrictEqual(expectedConfig); + + processCommits.mockRestore(); + }); +}); diff --git a/test/commit.test.ts b/test/commit.test.ts index fc87e851..b6351471 100644 --- a/test/commit.test.ts +++ b/test/commit.test.ts @@ -116,6 +116,23 @@ describe("Breaking Change", () => { ); expect(msg.breakingChange).toBe(true); }); + + test("Using BREAKING CHANGE footer, followed by a paragragh", () => { + const msg = new ConventionalCommitMessage( + dedent( + `feat: although this is breaking, it isn't (#123) + + BREAKING CHANGE: this will be ignored as it is followed + by a paragraph (<-- this one, as it is not prefixed with one (or more) space(s)) + + Implements #1234 + ` + ) + ); + expect(msg.breakingChange).toBe(false); + expect(msg.footers.length).toBe(1); + expect(msg.footers[0].value).toBe("#1234"); + }); }); // Validation of the body of a Commit Message @@ -234,28 +251,32 @@ describe("Footer", () => { expect(msg.footers[0].value).toBe("TEST-123"); }); - test("Discarded footer element due to paragraph break", () => { + test("Accept empty lines between footer elements", () => { const msg = new ConventionalCommitMessage( dedent( `fix: this commit has footers - Ignored: Item + Not-Ignored: Item Implements: TEST-123` ) ); - expect(msg.footers.length).toBe(1); - expect(msg.footers[0].token).toBe("Implements"); - expect(msg.footers[0].value).toBe("TEST-123"); + expect(msg.footers.length).toBe(2); + expect(msg.footers[0].token).toBe("Not-Ignored"); + expect(msg.footers[0].value).toBe("Item"); + expect(msg.footers[1].token).toBe("Implements"); + expect(msg.footers[1].value).toBe("TEST-123"); }); - test("Line break allowed after BREAKING-CHANGE", () => { + test("Ignore -------- cutting lines", () => { const msg = new ConventionalCommitMessage( dedent( `fix: this commit has footers BREAKING-CHANGE: This change is breaking + -------- + Implements: TEST-123` ) ); @@ -272,14 +293,16 @@ describe("Footer", () => { `chore: this contains a multiline footer element BREAKING-CHANGE: This is a multiline - paragraph in the footer` + paragraph in the footer + + This is the second paragraph in the BREAKING CHANGE footer` ) ); expect(msg.footers.length).toBe(1); expect(msg.footers[0].token).toBe("BREAKING-CHANGE"); expect(msg.footers[0].value).toBe( - "This is a multiline\n paragraph in the footer" + "This is a multiline\n paragraph in the footer\n\n This is the second paragraph in the BREAKING CHANGE footer" ); }); }); diff --git a/test/config.test.ts b/test/config.test.ts index 4dc6447d..fc8a541f 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -35,7 +35,7 @@ afterEach(() => { jest.restoreAllMocks(); }); -function withConfig(contents: string, func) { +function withConfig(contents: string, func: any) { const exists = jest.spyOn(fs, "existsSync").mockImplementation(() => true); const read = jest .spyOn(fs, "readFileSync") @@ -70,7 +70,6 @@ describe("Configurable options", () => { "C018", "C019", "C020", - "C022", "C023", "C024", ]; @@ -100,9 +99,9 @@ describe("Configurable options", () => { - C003 - C016 `), - config => { - expect(config.rules.get("C003").enabled).toEqual(false); - expect(config.rules.get("C016").enabled).toEqual(false); + (config: Configuration) => { + expect(config.rules.get("C003")?.enabled).toEqual(false); + expect(config.rules.get("C016")?.enabled).toEqual(false); expect(() => { new ConventionalCommitMessage( @@ -124,7 +123,7 @@ describe("Configurable options", () => { - XYZZY0123 - C002 `), - _config => { + (_config: Configuration) => { expect(coreWarning).toHaveBeenCalledTimes(1); } ); @@ -137,8 +136,8 @@ describe("Configurable options", () => { enable: - C026 `), - config => { - expect(config.rules.get("C026").enabled).toEqual(true); + (config: Configuration) => { + expect(config.rules.get("C026")?.enabled).toEqual(true); expect(() => { new ConventionalCommitMessage( @@ -161,7 +160,7 @@ describe("Configurable options", () => { - XYZZY0123 - C002 `), - _config => { + (_config: Configuration) => { expect(coreWarning).toHaveBeenCalledTimes(1); } ); @@ -169,19 +168,19 @@ describe("Configurable options", () => { }); test("Default maximum subject length", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { expect(config.maxSubjectLength).toEqual(80); }); }); test("Override maximum subject length", () => { - withConfig("max-subject-length: 100", config => { + withConfig("max-subject-length: 100", (config: Configuration) => { expect(config.maxSubjectLength).toEqual(100); }); }); test("Default tags", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { for (const [key, value] of Object.entries( _testData.DEFAULT_ACCEPTED_TAGS )) { @@ -201,7 +200,7 @@ describe("Configurable options", () => { disable: - C001 `), - config => { + (config: Configuration) => { const msg = new ConventionalCommitMessage( "typeA: do something requiring a custom type", undefined, @@ -220,7 +219,7 @@ describe("Configurable options", () => { description: Some custom type bump: true `), - config => { + (config: Configuration) => { expect(() => { new ConventionalCommitMessage( "typeA: do something requiring a custom type", @@ -241,7 +240,7 @@ describe("Configurable options", () => { disable: - C001 `), - config => { + (config: Configuration) => { const msg = new ConventionalCommitMessage( "typeA: do something requiring a custom type", undefined, @@ -259,7 +258,7 @@ describe("Configurable options", () => { disable: - C001 `), - config => { + (config: Configuration) => { const msg = new ConventionalCommitMessage( "revert: oopsie", undefined, @@ -278,7 +277,7 @@ describe("Configurable options", () => { disable: - C001 `), - config => { + (config: Configuration) => { const msg = new ConventionalCommitMessage( "revert: oopsie", undefined, @@ -305,7 +304,7 @@ describe("Configurable options", () => { disable: - C001 `), - config => { + (config: Configuration) => { // Types are overwritten, so expect "chore" not to be acceptable expect(() => { const msg2 = new ConventionalCommitMessage( @@ -325,7 +324,7 @@ describe("Configurable options", () => { perf: bump: true `), - config => { + (config: Configuration) => { const acceptedTypes = Object.keys(config.tags); expect(acceptedTypes).toHaveLength(3); @@ -345,7 +344,7 @@ describe("Configurable options", () => { improvement: bump: true `), - config => { + (config: Configuration) => { expect(config.tags["perf"].description).toEqual( _testData.DEFAULT_ACCEPTED_TAGS["perf"].description ); @@ -354,37 +353,37 @@ describe("Configurable options", () => { }); test("Default initial development value", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { expect(config.initialDevelopment).toEqual(true); }); }); test("Disable initial development", () => { - withConfig("initial-development: false", config => { + withConfig("initial-development: false", (config: Configuration) => { expect(config.initialDevelopment).toEqual(false); }); }); test("Default allowed branches", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { expect(config.allowedBranches).toEqual(".*"); }); }); test("Customize allowed branches", () => { - withConfig("allowed-branches: main", config => { + withConfig("allowed-branches: main", (config: Configuration) => { expect(config.allowedBranches).toEqual("main"); }); }); test("Default SdkVer create release branches", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { expect(config.sdkverCreateReleaseBranches).toBe(undefined); }); }); test("Default version prefix", () => { - withConfig("", config => { + withConfig("", (config: Configuration) => { expect(config.versionPrefix).toBe("*"); }); }); @@ -392,13 +391,13 @@ describe("Configurable options", () => { test("Boolean defaults", () => { withConfig( "version-scheme: sdkver\nsdkver-create-release-branches: true", - config => { + (config: Configuration) => { expect(config.sdkverCreateReleaseBranches).toBe("release/"); } ); withConfig( "version-scheme: sdkver\nsdkver-create-release-branches: false", - config => { + (config: Configuration) => { expect(config.sdkverCreateReleaseBranches).toBe(undefined); } ); @@ -407,7 +406,7 @@ describe("Configurable options", () => { test("String values", () => { withConfig( "version-scheme: sdkver\nsdkver-create-release-branches: some-release-prefix-\nversion-prefix: X", - config => { + (config: Configuration) => { expect(config.sdkverCreateReleaseBranches).toBe("some-release-prefix-"); expect(config.versionPrefix).toBe("X"); } @@ -423,10 +422,58 @@ describe("Configurable options", () => { }); withConfig( "version-scheme: semver\nsdkver-create-release-branches: true", - config => { + (config: Configuration) => { expect(config.sdkverCreateReleaseBranches).toBe("release/"); } ); expect(core.warning).toHaveBeenCalledTimes(1); }); }); + +describe("(Deep) Copy of Configuration", () => { + test("Default settings", () => { + const config = new Configuration(); + const copy = config.copy(); + expect(config).toEqual(copy); + }); + + test("Modification of copy does not affect original", () => { + const config = new Configuration(); + const copy = config.copy(); + + copy.maxSubjectLength = 100; + + expect(config.maxSubjectLength).toEqual(80); + }); + + test("Modification of original does not affect copy", () => { + const config = new Configuration(); + const copy = config.copy(); + + config.maxSubjectLength = 100; + + expect(copy.maxSubjectLength).toEqual(80); + }); + + test("Modification of nested object in copy does not affect original", () => { + const config = new Configuration(); + const copy = config.copy(); + + copy.tags["ci"].bump = true; + copy.setRuleActive("C001", false); + + expect(config.rules.get("C001")?.enabled).toEqual(true); + expect(config.tags["ci"].bump).toEqual(false); + }); + + test("Modification of nested object in original does not affect copy", () => { + const config = new Configuration(); + const copy = config.copy(); + + config.tags["ci"].bump = true; + config.setRuleActive("C001", false); + + expect(copy.rules.get("C001")?.enabled).toEqual(true); + expect(copy.tags["ci"].bump).toEqual(false); + }); +}); diff --git a/test/rules.test.ts b/test/rules.test.ts index 6cd7e9f4..e774c6d9 100644 --- a/test/rules.test.ts +++ b/test/rules.test.ts @@ -519,41 +519,6 @@ describe("Rules", () => { } }); - /** - * [C022] Footer should not contain any blank line(s) - */ - test(`[C022] Footer should not contain any blank line(s)`, () => { - for (const message of [ - dedent(`feat: multiple whitespaces in footers - - BREAKING CHANGE: Now we allow for whitespaces - - correct-token: value - - Implements: 1234`), - ]) { - assertRuleValidationError(message, getConventionalCommitRule("C022")); - } - - for (const message of [ - dedent(`feat: one empty line - - Implements: 1234`), - dedent(`feat(scope)!: multiple empty lines - - - Correct-token: value - Implements #1234 - `), - dedent(`chore: footers after one whiteline - - Implements #1234 - Implements: 1234`), - ]) { - assertRuleNoValidationError(message, getConventionalCommitRule("C022")); - } - }); - /** * [C024] A colon is required in git-trailers */ @@ -605,7 +570,7 @@ describe("Rules", () => { */ test(`[C026] A ticket reference is required in at least one footer value`, () => { const config = new Configuration(); - config.setRuleActivationStatus("C026", true); + config.setRuleActive("C026", true); for (const message of [ "test: no footer", diff --git a/test/semver.test.ts b/test/semver.test.ts index 06860012..de8419c5 100644 --- a/test/semver.test.ts +++ b/test/semver.test.ts @@ -278,6 +278,10 @@ describe("Build metadata", () => { describe("Helper functions", () => { test("Copy", () => { const original = SemVer.fromString("prefix1.2.3-prerelease+build"); + expect(original).not.toBeNull(); + if (original == null) { + return; + } const copy = SemVer.copy(original); expect(copy).not.toBe(original); diff --git a/test/test_utils.ts b/test/test_utils.ts index 8f04e4d7..cd19ebd6 100644 --- a/test/test_utils.ts +++ b/test/test_utils.ts @@ -17,7 +17,7 @@ import { createHash } from "crypto"; import { RequestError } from "@octokit/request-error"; -export const toICommit = msg => ({ +export const toICommit = (msg: string) => ({ message: msg, sha: createHash("sha1").update(msg).digest("hex").substring(0, 20), }); @@ -32,7 +32,7 @@ export const NONE_MSG2 = toICommit( "refactor: make something easier to maintain" ); export const NONE_MSG3 = toICommit("build: make something more efficiently"); -export const PRTITLE = type_ => `${type_}: simple PR title`; +export const PRTITLE = (type_: string) => `${type_}: simple PR title`; export const INITIAL_VERSION = "1.2.3"; export const PATCH_BUMPED_VERSION = "1.2.4"; @@ -51,7 +51,7 @@ export const DEFAULT_COMMIT_LIST = [ BASE_COMMIT, // order matters; newest first, base last ]; -export const mockGetInput = (setting, options?) => { +export const mockGetInput = (setting: string, _options?: unknown) => { switch (setting) { case "version-prefix": return "*"; @@ -65,7 +65,7 @@ export const mockGetInput = (setting, options?) => { throw new Error(`getInput("${setting}") not mocked`); }; -export const mockGetBooleanInput = (setting, options?) => { +export const mockGetBooleanInput = (setting: string, _options?: unknown) => { switch (setting) { case "create-release": return true; @@ -77,7 +77,7 @@ export const mockGetBooleanInput = (setting, options?) => { expect("error").toBe(`getBooleanInput("${setting}") not mocked`); return false; }; -export const getMockRequestError = statusCode => +export const getMockRequestError = (statusCode: number) => new RequestError("Mocked Error", statusCode, { request: { method: "GET", diff --git a/test/validate.test.ts b/test/validate.test.ts index 2851c225..d7e307eb 100644 --- a/test/validate.test.ts +++ b/test/validate.test.ts @@ -29,7 +29,7 @@ beforeEach(() => { jest.spyOn(github, "isPullRequestEvent").mockReturnValue(true); }); -const toICommit = msg => ({ message: msg, sha: "f00dface" }); +const toICommit = (msg: string) => ({ message: msg, sha: "f00dface" }); const NOK_1 = toICommit("foo: invalid commit"); const NOK_2 = toICommit("FIX : ~nvalid commit!"); const NOK_3 = toICommit("ci: long\nmultiline\n\n INVALID-COMMIT: withfooter"); From ca4282cd218e5cbebc5d7b2a852af94f566eab04 Mon Sep 17 00:00:00 2001 From: Kevin de Jong Date: Thu, 7 Dec 2023 17:15:13 +0100 Subject: [PATCH 5/5] feat: add `--verbose` option to the CLI to pretty print commits --- dist/cli/index.js | 130 ++++++++++++++++++++++++++++++++++++++-------- docs/cli.md | 9 +++- src/cli/cli.ts | 54 +++++++++++-------- src/cli/colors.ts | 20 +++++++ src/cli/utils.ts | 36 +++++++++++-- 5 files changed, 201 insertions(+), 48 deletions(-) create mode 100644 src/cli/colors.ts diff --git a/dist/cli/index.js b/dist/cli/index.js index 22fae4ab..2fa4309f 100755 --- a/dist/cli/index.js +++ b/dist/cli/index.js @@ -32312,17 +32312,13 @@ const dedent_1 = __importDefault(__nccwpck_require__(5281)); const core = __importStar(__nccwpck_require__(2186)); const fs = __importStar(__nccwpck_require__(7147)); const os = __importStar(__nccwpck_require__(2037)); +const Color = __importStar(__nccwpck_require__(7871)); const commit_1 = __nccwpck_require__(1730); const config_1 = __nccwpck_require__(6373); const errors_1 = __nccwpck_require__(6976); const commander_1 = __nccwpck_require__(4379); const utils_1 = __nccwpck_require__(2449); const program = new commander_1.Command(); -const gray = "\x1b[90m"; -const red = "\x1b[91m"; -const green = "\x1b[92m"; -const yellow = "\x1b[93m"; -const reset = "\x1b[0m"; program .name("commisery") .description("Commisery Conventional Commit Message Manager") @@ -32330,26 +32326,35 @@ program program .command("check") .description("Checks whether commit messages adhere to the Conventional Commits standard.") + .option("-v, --verbose", "also print commit message metadata.", false) .argument("[TARGET...]", `The \`TARGET\` can be: - a single commit hash - a file containing the commit message to check - a revision range that \`git rev-list\` can interpret When TARGET is omitted, 'HEAD' is implied.`) - .action(async (target) => { + .action(async (target, options) => { const config = new config_1.Configuration(program.opts().config); if (target.length === 0) { target = ["HEAD"]; } let messages = []; if (fs.existsSync(target.join(" "))) { - messages = [fs.readFileSync(target.join(" "), "utf8")]; + messages = [ + { + sha: target.join(" "), + body: fs.readFileSync(target.join(" "), "utf8"), + }, + ]; } else { messages = await (0, utils_1.getCommitMessages)(target); } for (const message of messages) { try { - new commit_1.ConventionalCommitMessage(message, undefined, config); + const commitmessage = new commit_1.ConventionalCommitMessage(message.body, message.sha, config); + if (options.verbose) { + (0, utils_1.prettyPrintCommitMessage)(commitmessage); + } } catch (error) { if (error instanceof errors_1.ConventionalCommitError) { @@ -32366,38 +32371,73 @@ program .command("overview") .description("Lists the accepted Conventional Commit types and Rules (including description)") .action(() => { - var _a, _b; + var _a; const config = new config_1.Configuration(program.opts().config); core.info((0, dedent_1.default)(` Conventional Commit types -------------------------`)); for (const key in config.tags) { const bumps = config.tags[key].bump && key !== "fix" - ? ` ${yellow}(bumps patch)${reset}` + ? ` ${Color.YELLOW("(bumps patch)")}` : ""; - core.info(`${key}: ${gray}${config.tags[key].description}${reset}${bumps}`); + core.info(`${key}: ${Color.GRAY((_a = config.tags[key].description) !== null && _a !== void 0 ? _a : "")}${bumps}`); } core.info(os.EOL); core.info((0, dedent_1.default)(` Commisery Validation rules -------------------------- - [${green}o${reset}]: ${gray}rule is enabled${reset}, [${red}x${reset}]: ${gray}rule is disabled${reset} + [${Color.GREEN("o")}]: ${Color.GRAY("rule is enabled")}, [${Color.RED("x")}]: ${Color.GRAY("rule is disabled")} `)); core.info(os.EOL); - for (const rule in config.rules) { - const status = ((_a = config.rules.get(rule)) === null || _a === void 0 ? void 0 : _a.enabled) - ? `${green}o${reset}` - : `${red}x${reset}`; - core.info(`[${status}] ${rule}: ${gray}${(_b = config.rules.get(rule)) === null || _b === void 0 ? void 0 : _b.description}${reset}`); - } + config.rules.forEach((rule, key) => { + var _a; + const status = rule.enabled + ? `${Color.GREEN("o")}` + : `${Color.RED("x")}`; + core.info(`[${status}] ${key}: ${Color.GRAY((_a = rule.description) !== null && _a !== void 0 ? _a : "")}`); + }); }); program.parse(); +/***/ }), + +/***/ 7871: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.YELLOW = exports.GREEN = exports.RED = exports.GRAY = void 0; +const GRAY = (message) => `\x1b[90m${message}\x1b[0m`; +exports.GRAY = GRAY; +const RED = (message) => `\x1b[91m${message}\x1b[0m`; +exports.RED = RED; +const GREEN = (message) => `\x1b[92m${message}\x1b[0m`; +exports.GREEN = GREEN; +const YELLOW = (message) => `\x1b[93m${message}\x1b[0m`; +exports.YELLOW = YELLOW; + + /***/ }), /***/ 2449: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -32416,9 +32456,39 @@ program.parse(); * See the License for the specific language governing permissions and * limitations under the License. */ +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (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; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getCommitMessages = exports.getRootPath = void 0; +exports.prettyPrintCommitMessage = exports.getCommitMessages = exports.getRootPath = void 0; const simple_git_1 = __nccwpck_require__(9103); +const Color = __importStar(__nccwpck_require__(7871)); +const os = __importStar(__nccwpck_require__(2037)); +const dedent_1 = __importDefault(__nccwpck_require__(5281)); +const semver_1 = __nccwpck_require__(8593); let __ROOT_PATH = undefined; /** * Determine the root path of the GIT project @@ -32475,7 +32545,7 @@ async function getCommitMessages(target) { const messages = []; for (const hash of commitHashes) { try { - messages.push(await getCommitMessage(hash)); + messages.push({ sha: hash, body: await getCommitMessage(hash) }); } catch (error) { continue; @@ -32484,6 +32554,24 @@ async function getCommitMessages(target) { return messages; } exports.getCommitMessages = getCommitMessages; +function prettyPrintCommitMessage(commit) { + var _a, _b; + console.log(""); + console.log((0, dedent_1.default)(` + ${Color.RED(`[[---- (Commit ${commit.hexsha}) ----]]`)} + ${Color.GREEN("Type")}: ${commit.type} + ${Color.GREEN("Scope")}: ${(_a = commit.scope) !== null && _a !== void 0 ? _a : "None"} + ${Color.GREEN("Breaking Change")}: ${commit.breakingChange ? Color.RED("Yes") : Color.GREEN("No")} + ${Color.GREEN("Bump")}: ${semver_1.SemVerType[commit.bump]} + ${Color.GREEN("Description")}: ${commit.description} + ${Color.GREEN("Body")}: ${Color.GRAY((_b = commit.body) !== null && _b !== void 0 ? _b : "None")} + ${Color.GREEN("Footers")}: + ${commit.footers + .map(footer => `${footer.token}: ${Color.GRAY(footer.value)}`) + .join(os.EOL)} + `)); +} +exports.prettyPrintCommitMessage = prettyPrintCommitMessage; /***/ }), diff --git a/docs/cli.md b/docs/cli.md index d5c79e2d..d79c1d40 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -31,16 +31,21 @@ Usage: commisery check [options] [TARGET...] Checks whether commit messages adhere to the Conventional Commits standard. Arguments: - TARGET The `TARGET` can be: + TARGET The `TARGET` can be: - a single commit hash - a file containing the commit message to check - a revision range that `git rev-list` can interpret When TARGET is omitted, 'HEAD' is implied. Options: - -h, --help display help for command + -v, --verbose also print commit message metadata (default: false) + -h, --help display help for command ``` +> :bulb: flag will provide an overview of the parsed Conventional Commits elements for each correct message encountered. +> This can be valuable to investigate scenarios in which you expected a different version bump than +> the actual output of the `bump`-action. + ### (Pre-) Commit hook You can use the CLI as a hook in Git to check messages you wrote by creating a `.git/hooks/commit-msg` file with these contents: diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 0d734230..fe8669d1 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -21,18 +21,15 @@ import * as core from "@actions/core"; import * as fs from "fs"; import * as os from "os"; +import * as Color from "./colors"; + import { ConventionalCommitMessage } from "../commit"; import { Configuration } from "../config"; import { ConventionalCommitError } from "../errors"; import { Command } from "commander"; -import { getCommitMessages } from "./utils"; +import { getCommitMessages, prettyPrintCommitMessage } from "./utils"; const program = new Command(); -const gray = "\x1b[90m"; -const red = "\x1b[91m"; -const green = "\x1b[92m"; -const yellow = "\x1b[93m"; -const reset = "\x1b[0m"; program .name("commisery") @@ -44,6 +41,7 @@ program .description( "Checks whether commit messages adhere to the Conventional Commits standard." ) + .option("-v, --verbose", "also print commit message metadata.", false) .argument( "[TARGET...]", `The \`TARGET\` can be: @@ -52,23 +50,36 @@ program - a revision range that \`git rev-list\` can interpret When TARGET is omitted, 'HEAD' is implied.` ) - .action(async (target: string[]) => { + .action(async (target: string[], options) => { const config = new Configuration(program.opts().config); if (target.length === 0) { target = ["HEAD"]; } - let messages: string[] = []; + let messages: { sha: string; body: string }[] = []; if (fs.existsSync(target.join(" "))) { - messages = [fs.readFileSync(target.join(" "), "utf8")]; + messages = [ + { + sha: target.join(" "), + body: fs.readFileSync(target.join(" "), "utf8"), + }, + ]; } else { messages = await getCommitMessages(target); } for (const message of messages) { try { - new ConventionalCommitMessage(message, undefined, config); + const commitmessage = new ConventionalCommitMessage( + message.body, + message.sha, + config + ); + + if (options.verbose) { + prettyPrintCommitMessage(commitmessage); + } } catch (error: unknown) { if (error instanceof ConventionalCommitError) { for (const err of error.errors) { @@ -99,10 +110,10 @@ program for (const key in config.tags) { const bumps: string = config.tags[key].bump && key !== "fix" - ? ` ${yellow}(bumps patch)${reset}` + ? ` ${Color.YELLOW("(bumps patch)")}` : ""; core.info( - `${key}: ${gray}${config.tags[key].description}${reset}${bumps}` + `${key}: ${Color.GRAY(config.tags[key].description ?? "")}${bumps}` ); } @@ -112,21 +123,20 @@ program dedent(` Commisery Validation rules -------------------------- - [${green}o${reset}]: ${gray}rule is enabled${reset}, [${red}x${reset}]: ${gray}rule is disabled${reset} + [${Color.GREEN("o")}]: ${Color.GRAY("rule is enabled")}, [${Color.RED( + "x" + )}]: ${Color.GRAY("rule is disabled")} `) ); core.info(os.EOL); - for (const rule in config.rules) { - const status: string = config.rules.get(rule)?.enabled - ? `${green}o${reset}` - : `${red}x${reset}`; - core.info( - `[${status}] ${rule}: ${gray}${config.rules.get(rule) - ?.description}${reset}` - ); - } + config.rules.forEach((rule, key) => { + const status: string = rule.enabled + ? `${Color.GREEN("o")}` + : `${Color.RED("x")}`; + core.info(`[${status}] ${key}: ${Color.GRAY(rule.description ?? "")}`); + }); }); program.parse(); diff --git a/src/cli/colors.ts b/src/cli/colors.ts new file mode 100644 index 00000000..5cc534e1 --- /dev/null +++ b/src/cli/colors.ts @@ -0,0 +1,20 @@ +/** + * Copyright (C) 2023, TomTom (http://tomtom.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const GRAY = (message: string): string => `\x1b[90m${message}\x1b[0m`; +export const RED = (message: string): string => `\x1b[91m${message}\x1b[0m`; +export const GREEN = (message: string): string => `\x1b[92m${message}\x1b[0m`; +export const YELLOW = (message: string): string => `\x1b[93m${message}\x1b[0m`; diff --git a/src/cli/utils.ts b/src/cli/utils.ts index 37baf9a5..ab094eba 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -15,6 +15,11 @@ */ import { GitError, simpleGit } from "simple-git"; +import { ConventionalCommitMessage } from "../commit"; +import * as Color from "./colors"; +import * as os from "os"; +import dedent from "dedent"; +import { SemVerType } from "../semver"; let __ROOT_PATH: string | undefined = undefined; @@ -61,7 +66,9 @@ async function getCommitMessage(target: string): Promise { * Retrieves a list of commit messages based on the provided target * parameter */ -export async function getCommitMessages(target: string[]): Promise { +export async function getCommitMessages( + target: string[] +): Promise<{ sha: string; body: string }[]> { const git = simpleGit(await getRootPath()); let commitHashes: string[] = []; @@ -76,10 +83,10 @@ export async function getCommitMessages(target: string[]): Promise { commitHashes.push(target[0]); } - const messages: string[] = []; + const messages: { sha: string; body: string }[] = []; for (const hash of commitHashes) { try { - messages.push(await getCommitMessage(hash)); + messages.push({ sha: hash, body: await getCommitMessage(hash) }); } catch (error: unknown) { continue; } @@ -87,3 +94,26 @@ export async function getCommitMessages(target: string[]): Promise { return messages; } + +export function prettyPrintCommitMessage( + commit: ConventionalCommitMessage +): void { + console.log(""); + console.log( + dedent(` + ${Color.RED(`[[---- (Commit ${commit.hexsha}) ----]]`)} + ${Color.GREEN("Type")}: ${commit.type} + ${Color.GREEN("Scope")}: ${commit.scope ?? "None"} + ${Color.GREEN("Breaking Change")}: ${ + commit.breakingChange ? Color.RED("Yes") : Color.GREEN("No") + } + ${Color.GREEN("Bump")}: ${SemVerType[commit.bump]} + ${Color.GREEN("Description")}: ${commit.description} + ${Color.GREEN("Body")}: ${Color.GRAY(commit.body ?? "None")} + ${Color.GREEN("Footers")}: + ${commit.footers + .map(footer => `${footer.token}: ${Color.GRAY(footer.value)}`) + .join(os.EOL)} + `) + ); +}