@elsikora/setup-wizard
Version:
Setup Wizard - CLI scaffolding utility
197 lines (194 loc) • 9.06 kB
JavaScript
import { EModule } from '../../domain/enum/module.enum.js';
import { EPackageJsonDependencyType } from '../../domain/enum/package-json-dependency-type.enum.js';
import { NodeCommandService } from '../../infrastructure/service/node-command.service.js';
import { COMMITLINT_CONFIG_CORE_DEPENDENCIES } from '../constant/commitlint-config-core-dependencies.constant.js';
import { COMMITLINT_CONFIG_FILE_NAMES } from '../constant/commitlint-config-file-names.constant.js';
import { COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT } from '../constant/commitlint-config-husky-commit-msg-script.constant.js';
import { COMMITLINT_CONFIG_HUSKY_PRE_PUSH_SCRIPT } from '../constant/commitlint-config-husky-pre-push-script.constant.js';
import { COMMITLINT_CONFIG } from '../constant/commitlint-config.constant.js';
import { PackageJsonService } from './package-json.service.js';
/**
* Service for setting up and managing Commitlint and Commitizen configuration.
* Provides functionality to enforce consistent commit message formats using Commitlint
* and simplify commit creation using Commitizen.
*/
class CommitlintModuleService {
/** CLI interface service for user interaction */
CLI_INTERFACE_SERVICE;
/** Command service for executing shell commands */
COMMAND_SERVICE;
/** Configuration service for managing app configuration */
CONFIG_SERVICE;
/** File system service for file operations */
FILE_SYSTEM_SERVICE;
/** Service for managing package.json */
PACKAGE_JSON_SERVICE;
/**
* Initializes a new instance of the CommitlintModuleService.
* @param cliInterfaceService - Service for CLI user interactions
* @param fileSystemService - Service for file system operations
* @param configService - Service for managing app configuration
*/
constructor(cliInterfaceService, fileSystemService, configService) {
this.CLI_INTERFACE_SERVICE = cliInterfaceService;
this.FILE_SYSTEM_SERVICE = fileSystemService;
this.COMMAND_SERVICE = new NodeCommandService(cliInterfaceService);
this.PACKAGE_JSON_SERVICE = new PackageJsonService(fileSystemService, this.COMMAND_SERVICE);
this.CONFIG_SERVICE = configService;
}
/**
* Handles existing Commitlint/Commitizen setup.
* Checks for existing configuration files and asks if user wants to remove them.
* @returns Promise resolving to true if setup should proceed, false otherwise
*/
async handleExistingSetup() {
const existingFiles = await this.findExistingConfigFiles();
if (existingFiles.length > 0) {
const messageLines = ["Existing Commitlint/Commitizen configuration files detected:"];
messageLines.push("");
if (existingFiles.length > 0) {
for (const file of existingFiles) {
messageLines.push(`- ${file}`);
}
}
messageLines.push("", "Do you want to delete them?");
const shouldDelete = await this.CLI_INTERFACE_SERVICE.confirm(messageLines.join("\n"), true);
if (shouldDelete) {
await Promise.all(existingFiles.map((file) => this.FILE_SYSTEM_SERVICE.deleteFile(file)));
}
else {
this.CLI_INTERFACE_SERVICE.warn("Existing Commitlint/Commitizen configuration files detected. Setup aborted.");
return false;
}
}
return true;
}
/**
* Installs and configures Commitlint and Commitizen.
* Sets up configuration files, git hooks, and package.json scripts.
* @returns Promise resolving to the module setup result
*/
async install() {
try {
if (!(await this.shouldInstall())) {
return { wasInstalled: false };
}
if (!(await this.handleExistingSetup())) {
return { wasInstalled: false };
}
await this.setupCommitlint();
return { wasInstalled: true };
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError("Failed to complete Commitlint setup", error);
throw error;
}
}
/**
* Determines if Commitlint/Commitizen should be installed.
* Asks the user if they want to set up these tools for their project.
* Uses the saved config value as default if it exists.
* @returns Promise resolving to true if the module should be installed, false otherwise
*/
async shouldInstall() {
try {
return await this.CLI_INTERFACE_SERVICE.confirm("Do you want to set up Commitlint and Commitizen for your project?", await this.CONFIG_SERVICE.isModuleEnabled(EModule.COMMITLINT));
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError("Failed to get user confirmation", error);
return false;
}
}
/**
* Creates the Commitlint configuration file.
*/
async createConfigs() {
await this.FILE_SYSTEM_SERVICE.writeFile("commitlint.config.js", COMMITLINT_CONFIG, "utf8");
}
/**
* Displays a summary of the setup results.
*/
displaySetupSummary() {
const summary = ["Commitlint and Commitizen configuration has been created.", "", "Generated scripts:", "- npm run commit (for commitizen)", "", "Configuration files:", "- commitlint.config.js", "- .husky/commit-msg", "- .husky/pre-push", "", "Husky git hooks have been set up to validate your commits and branch names.", "Use 'npm run commit' to create commits using the interactive commitizen interface."];
this.CLI_INTERFACE_SERVICE.note("Commitlint Setup", summary.join("\n"));
}
/**
* Finds existing Commitlint/Commitizen configuration files.
* @returns Promise resolving to an array of file paths for existing configuration files
*/
async findExistingConfigFiles() {
const existingFiles = [];
for (const file of COMMITLINT_CONFIG_FILE_NAMES) {
if (await this.FILE_SYSTEM_SERVICE.isPathExists(file)) {
existingFiles.push(file);
}
}
if (await this.FILE_SYSTEM_SERVICE.isPathExists(".husky/commit-msg")) {
existingFiles.push(".husky/commit-msg");
}
if (await this.FILE_SYSTEM_SERVICE.isPathExists(".husky/pre-push")) {
existingFiles.push(".husky/pre-push");
}
return existingFiles;
}
/**
* Sets up Commitlint and Commitizen.
* Installs dependencies, creates configuration files, and configures git hooks.
*/
async setupCommitlint() {
this.CLI_INTERFACE_SERVICE.startSpinner("Setting up Commitlint and Commitizen configuration...");
try {
await this.PACKAGE_JSON_SERVICE.installPackages(COMMITLINT_CONFIG_CORE_DEPENDENCIES, "latest", EPackageJsonDependencyType.DEV);
await this.createConfigs();
await this.setupHusky();
await this.setupPackageJsonConfigs();
await this.setupScripts();
this.CLI_INTERFACE_SERVICE.stopSpinner("Commitlint and Commitizen configuration completed successfully!");
this.displaySetupSummary();
}
catch (error) {
this.CLI_INTERFACE_SERVICE.stopSpinner("Failed to setup Commitlint and Commitizen configuration");
throw error;
}
}
/**
* Sets up Husky git hooks.
* Initializes Husky, adds prepare script, and creates commit-msg and pre-push hooks.
*/
async setupHusky() {
// Initialize husky
await this.COMMAND_SERVICE.execute("npx husky");
// Add prepare script if it doesn't exist
await this.PACKAGE_JSON_SERVICE.addScript("prepare", "husky");
await this.COMMAND_SERVICE.execute("mkdir -p .husky");
// Create commit-msg hook
await this.FILE_SYSTEM_SERVICE.writeFile(".husky/commit-msg", COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT, "utf8");
await this.COMMAND_SERVICE.execute("chmod +x .husky/commit-msg");
// Create pre-push hook
await this.FILE_SYSTEM_SERVICE.writeFile(".husky/pre-push", COMMITLINT_CONFIG_HUSKY_PRE_PUSH_SCRIPT, "utf8");
await this.COMMAND_SERVICE.execute("chmod +x .husky/pre-push");
}
/**
* Sets up Commitizen configuration in package.json.
*/
async setupPackageJsonConfigs() {
const packageJson = await this.PACKAGE_JSON_SERVICE.get();
if (!packageJson.config) {
packageJson.config = {};
}
packageJson.config.commitizen = {
path: "@elsikora/commitizen-plugin-commitlint-ai",
};
await this.PACKAGE_JSON_SERVICE.set(packageJson);
}
/**
* Sets up npm scripts for Commitizen.
* Adds 'commit' script for starting the Commitizen CLI.
*/
async setupScripts() {
await this.PACKAGE_JSON_SERVICE.addScript("commit", "cz");
}
}
export { CommitlintModuleService };
//# sourceMappingURL=commitlint-module.service.js.map