From d6bcf90fbfe2d1d805b8c5e66951a84d01583023 Mon Sep 17 00:00:00 2001 From: KevinDeJong-TomTom <62094856+KevinDeJong-TomTom@users.noreply.github.com> Date: Sat, 28 May 2022 08:37:19 +0200 Subject: [PATCH] refactor: split module for maintanability (#27) --- CHANGELOG.md | 4 + dist/index.js | 221 +++++++++++++++++++++++++++++++-------------- src/commisery.ts | 104 +++++++++++++++++++++ src/environment.ts | 77 ++++++++++++++++ src/main.ts | 147 ++---------------------------- 5 files changed, 346 insertions(+), 207 deletions(-) create mode 100644 src/commisery.ts create mode 100644 src/environment.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d6350a3c..b3002f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Changed +- Improved user feedback during execution of the action + ## [1.0.1] - 2022-05-18 ### Fixed - The requirements.txt file is now properly included in the npm package diff --git a/dist/index.js b/dist/index.js index 190a4201..cec1a111 100644 --- a/dist/index.js +++ b/dist/index.js @@ -9958,7 +9958,7 @@ function wrappy (fn, cb) { /***/ }), -/***/ 399: +/***/ 8604: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -9978,29 +9978,6 @@ function wrappy (fn, cb) { * 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 __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) { @@ -10011,11 +9988,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.is_commit_valid = exports.get_commits = void 0; const core = __nccwpck_require__(2186); const exec = __nccwpck_require__(1514); const github = __nccwpck_require__(5438); const fs = __nccwpck_require__(7147); -const path = __importStar(__nccwpck_require__(1017)); /** * Strips ANSI color codes from the provided message * @param message @@ -10045,46 +10022,6 @@ function get_error_subjects(message) { } return errors; } -/** - * Confirms whether Python >=3.8 and pip are present on the runner - */ -function check_prerequisites() { - return __awaiter(this, void 0, void 0, function* () { - const python_version_re = /Python\s*(\d+)\.(\d+)\.(\d+)/; - const { stdout: python_version } = yield exec.getExecOutput("python3", ["--version"], { silent: true }); - const match = python_version_re.exec(python_version); - if (!match || match.length != 4) { - throw new Error("Unable to determine the installed Python version."); - } - if (!(parseInt(match[1]) == 3 && parseInt(match[2]) >= 8)) { - throw new Error(`Incorrect Python version installed; found ${match[1]}.${match[2]}.${match[3]}, expected >= 3.8.0`); - } - try { - const { stdout: pip_version } = yield exec.getExecOutput("python3", ["-m", "pip", "--version"], { silent: true }); - } - catch (_a) { - throw new Error("Unable to determine the installed Pip version."); - } - }); -} -/** - * Installs the latest version of commisery - */ -function prepare_environment() { - return __awaiter(this, void 0, void 0, function* () { - // Ensure Python (>= 3.8) and pip are installed - yield check_prerequisites(); - // Install latest version of commisery - yield exec.exec("python3", [ - "-m", - "pip", - "install", - "--upgrade", - "--requirement", - path.join(__dirname, "requirements.txt"), - ]); - }); -} /** * Retrieves a list of commits associated with the specified Pull Request * @param owner GitHub owner @@ -10105,6 +10042,7 @@ function get_commits(owner, repo, pullrequest_id) { return commits; }); } +exports.get_commits = get_commits; /** * Validates the commit object against the Conventional Commit convention * @param commit @@ -10130,17 +10068,161 @@ function is_commit_valid(commit) { return [stderr == "", get_error_subjects(stderr)]; }); } +exports.is_commit_valid = is_commit_valid; + + +/***/ }), + +/***/ 6869: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +/** + * Copyright (C) 2020-2022, 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. + */ +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 __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.prepare_environment = void 0; +const exec = __nccwpck_require__(1514); +const path = __importStar(__nccwpck_require__(1017)); +/** + * Checks whether the provided Python version is present + * + * @param major Major version + * @param minor Minor version + */ +function check_python_prerequisites(major, minor) { + return __awaiter(this, void 0, void 0, function* () { + const python_version_re = /Python\s*(\d+)\.(\d+)\.(\d+)/; + const { stdout: python_version } = yield exec.getExecOutput("python3", ["--version"], { silent: true }); + const match = python_version_re.exec(python_version); + if (!match || match.length != 4) { + throw new Error("Unable to determine the installed Python version."); + } + if (!(parseInt(match[1]) == major && parseInt(match[2]) >= minor)) { + throw new Error(`Incorrect Python version installed; found ${match[1]}.${match[2]}.${match[3]}, expected >= ${major}.${minor}.0`); + } + try { + const { stdout: pip_version } = yield exec.getExecOutput("python3", ["-m", "pip", "--version"], { silent: true }); + } + catch (_a) { + throw new Error("Unable to determine the installed Pip version."); + } + }); +} +/** + * Prepares the environment for using commisery + */ +function prepare_environment() { + return __awaiter(this, void 0, void 0, function* () { + // Ensure Python (>= 3.8) and pip are installed + yield check_python_prerequisites(3, 8); + // Install latest version of commisery + yield exec.exec("python3", [ + "-m", + "pip", + "install", + "--upgrade", + "--requirement", + path.join(__dirname, "requirements.txt"), + ], { silent: true }); + }); +} +exports.prepare_environment = prepare_environment; + + +/***/ }), + +/***/ 399: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +/** + * Copyright (C) 2020-2022, 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. + */ +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 })); +const core = __nccwpck_require__(2186); +const environment_1 = __nccwpck_require__(6869); +const commisery_1 = __nccwpck_require__(8604); function run() { return __awaiter(this, void 0, void 0, function* () { // Ensure that commisery is installed try { - yield prepare_environment(); + console.log("🌲 Preparing environment..."); + yield (0, environment_1.prepare_environment)(); let [owner, repo] = (process.env.GITHUB_REPOSITORY || "").split("/"); // Validate each commit against Conventional Commit standard - let commits = yield get_commits(owner, repo, core.getInput("pull_request")); + let commits = yield (0, commisery_1.get_commits)(owner, repo, core.getInput("pull_request")); let success = true; + console.log("🚀 Validating your commit messages..."); for (const commit of commits) { - let [valid, errors] = yield is_commit_valid(commit); + let [valid, errors] = yield (0, commisery_1.is_commit_valid)(commit); if (!valid) { core.summary .addHeading(commit.commit.message, 2) @@ -10156,6 +10238,9 @@ function run() { // Post summary core.summary.write(); } + else { + console.log("✅ Your commit messages comply to the conventional commit standard!"); + } } catch (ex) { core.setFailed(ex.message); diff --git a/src/commisery.ts b/src/commisery.ts new file mode 100644 index 00000000..9705bcb0 --- /dev/null +++ b/src/commisery.ts @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2020-2022, 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. + */ + +const core = require("@actions/core"); +const exec = require("@actions/exec"); +const github = require("@actions/github"); +const fs = require("fs"); + +/** + * Strips ANSI color codes from the provided message + * @param message + * @returns message without ANSI color codes + */ +function strip_ansicolor(message: string) { + const pattern = [ + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + ].join("|"); + + return message.replace(new RegExp(pattern, "g"), ""); +} + +/** + * Converts error message into GitHub accepted format + * @param message + * @returns multiline message + */ +function get_error_subjects(message: string) { + let errors: string[] = []; + + for (var line of strip_ansicolor(message).split("\n")) { + if (line.startsWith(".commit-message") && line.indexOf(": error:") > -1) { + errors.push(line); + } else if (line.length > 0) { + errors[errors.length - 1] += `\n${line}`; + } + } + + return errors; +} + +/** + * Retrieves a list of commits associated with the specified Pull Request + * @param owner GitHub owner + * @param repo GitHub repository + * @param pullrequest_id GitHub Pullrequest ID + * @returns List of commit objects + */ +export async function get_commits( + owner: string, + repo: string, + pullrequest_id: string +) { + const github_token = core.getInput("token"); + const octokit = github.getOctokit(github_token); + + // Retrieve commits from provided Pull Request + const { data: commits } = await octokit.rest.pulls.listCommits({ + owner: owner, + repo: repo, + pull_number: pullrequest_id, + }); + + return commits; +} + +/** + * Validates the commit object against the Conventional Commit convention + * @param commit + * @returns + */ +export async function is_commit_valid(commit): Promise<[boolean, string[]]> { + // Provide the commit message as file + await fs.writeFileSync(".commit-message", commit.commit.message); + + let stderr = ""; + + try { + await exec.exec("commisery-verify-msg", [".commit-message"], { + ignoreReturnCode: true, + silent: true, + listeners: { + stderr: (data: Buffer): string => (stderr += data.toString()), + }, + }); + } catch (error) { + core.debug("Error detected while executing commisery"); + } + + return [stderr == "", get_error_subjects(stderr)]; +} diff --git a/src/environment.ts b/src/environment.ts new file mode 100644 index 00000000..5795430c --- /dev/null +++ b/src/environment.ts @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2020-2022, 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. + */ + +const exec = require("@actions/exec"); + +import * as path from "path"; + +/** + * Checks whether the provided Python version is present + * + * @param major Major version + * @param minor Minor version + */ +async function check_python_prerequisites(major, minor) { + const python_version_re = /Python\s*(\d+)\.(\d+)\.(\d+)/; + const { stdout: python_version } = await exec.getExecOutput( + "python3", + ["--version"], + { silent: true } + ); + const match = python_version_re.exec(python_version); + + if (!match || match.length != 4) { + throw new Error("Unable to determine the installed Python version."); + } + + if (!(parseInt(match[1]) == major && parseInt(match[2]) >= minor)) { + throw new Error( + `Incorrect Python version installed; found ${match[1]}.${match[2]}.${match[3]}, expected >= ${major}.${minor}.0` + ); + } + + try { + const { stdout: pip_version } = await exec.getExecOutput( + "python3", + ["-m", "pip", "--version"], + { silent: true } + ); + } catch { + throw new Error("Unable to determine the installed Pip version."); + } +} + +/** + * Prepares the environment for using commisery + */ +export async function prepare_environment() { + // Ensure Python (>= 3.8) and pip are installed + await check_python_prerequisites(3, 8); + + // Install latest version of commisery + await exec.exec( + "python3", + [ + "-m", + "pip", + "install", + "--upgrade", + "--requirement", + path.join(__dirname, "requirements.txt"), + ], + { silent: true } + ); +} diff --git a/src/main.ts b/src/main.ts index d62981fe..a959d58f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -15,150 +15,14 @@ */ const core = require("@actions/core"); -const exec = require("@actions/exec"); -const github = require("@actions/github"); -const fs = require("fs"); -import * as path from "path"; - -/** - * Strips ANSI color codes from the provided message - * @param message - * @returns message without ANSI color codes - */ -function strip_ansicolor(message: string) { - const pattern = [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", - ].join("|"); - - return message.replace(new RegExp(pattern, "g"), ""); -} - -/** - * Converts error message into GitHub accepted format - * @param message - * @returns multiline message - */ -function get_error_subjects(message: string) { - let errors: string[] = []; - - for (var line of strip_ansicolor(message).split("\n")) { - if (line.startsWith(".commit-message") && line.indexOf(": error:") > -1) { - errors.push(line); - } else if (line.length > 0) { - errors[errors.length - 1] += `\n${line}`; - } - } - - return errors; -} - -/** - * Confirms whether Python >=3.8 and pip are present on the runner - */ -async function check_prerequisites() { - const python_version_re = /Python\s*(\d+)\.(\d+)\.(\d+)/; - const { stdout: python_version } = await exec.getExecOutput( - "python3", - ["--version"], - { silent: true } - ); - const match = python_version_re.exec(python_version); - - if (!match || match.length != 4) { - throw new Error("Unable to determine the installed Python version."); - } - - if (!(parseInt(match[1]) == 3 && parseInt(match[2]) >= 8)) { - throw new Error( - `Incorrect Python version installed; found ${match[1]}.${match[2]}.${match[3]}, expected >= 3.8.0` - ); - } - - try { - const { stdout: pip_version } = await exec.getExecOutput( - "python3", - ["-m", "pip", "--version"], - { silent: true } - ); - } catch { - throw new Error("Unable to determine the installed Pip version."); - } -} - -/** - * Installs the latest version of commisery - */ -async function prepare_environment() { - // Ensure Python (>= 3.8) and pip are installed - await check_prerequisites(); - - // Install latest version of commisery - await exec.exec("python3", [ - "-m", - "pip", - "install", - "--upgrade", - "--requirement", - path.join(__dirname, "requirements.txt"), - ]); -} - -/** - * Retrieves a list of commits associated with the specified Pull Request - * @param owner GitHub owner - * @param repo GitHub repository - * @param pullrequest_id GitHub Pullrequest ID - * @returns List of commit objects - */ -async function get_commits( - owner: string, - repo: string, - pullrequest_id: string -) { - const github_token = core.getInput("token"); - const octokit = github.getOctokit(github_token); - - // Retrieve commits from provided Pull Request - const { data: commits } = await octokit.rest.pulls.listCommits({ - owner: owner, - repo: repo, - pull_number: pullrequest_id, - }); - - return commits; -} - -/** - * Validates the commit object against the Conventional Commit convention - * @param commit - * @returns - */ -async function is_commit_valid(commit): Promise<[boolean, string[]]> { - // Provide the commit message as file - await fs.writeFileSync(".commit-message", commit.commit.message); - - let stderr = ""; - - try { - await exec.exec("commisery-verify-msg", [".commit-message"], { - ignoreReturnCode: true, - silent: true, - listeners: { - stderr: (data: Buffer): string => (stderr += data.toString()), - }, - }); - } catch (error) { - core.debug("Error detected while executing commisery"); - } - - return [stderr == "", get_error_subjects(stderr)]; -} +import { prepare_environment } from "./environment"; +import { is_commit_valid, get_commits } from "./commisery"; async function run() { // Ensure that commisery is installed try { + console.log("🌲 Preparing environment..."); await prepare_environment(); let [owner, repo] = (process.env.GITHUB_REPOSITORY || "").split("/"); @@ -167,6 +31,7 @@ async function run() { let commits = await get_commits(owner, repo, core.getInput("pull_request")); let success = true; + console.log("🚀 Validating your commit messages..."); for (const commit of commits) { let [valid, errors] = await is_commit_valid(commit); @@ -192,6 +57,10 @@ async function run() { // Post summary core.summary.write(); + } else { + console.log( + "✅ Your commit messages comply to the conventional commit standard!" + ); } } catch (ex) { core.setFailed((ex as Error).message);