@elsikora/setup-wizard
Version:
Setup Wizard - CLI scaffolding utility
529 lines (526 loc) • 27.9 kB
JavaScript
import { ECommitlintMode } from '../../domain/enum/commitlint-mode.enum.js';
import { ECommitlintProvider } from '../../domain/enum/commitlint-provider.enum.js';
import { ECommitlintTicketMissingBranchLintBehavior } from '../../domain/enum/commitlint-ticket-missing-branch-lint-behavior.enum.js';
import { ECommitlintTicketNormalization } from '../../domain/enum/commitlint-ticket-normalization.enum.js';
import { ECommitlintTicketSource } from '../../domain/enum/commitlint-ticket-source.enum.js';
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_AI_DEFAULTS, COMMITLINT_AI_CONFIG } from '../constant/commitlint/ai-config.constant.js';
import { COMMITLINT_CONFIG } from '../constant/commitlint/config.constant.js';
import { COMMITLINT_CONFIG_CORE_DEPENDENCIES } from '../constant/commitlint/core-dependencies.constant.js';
import { COMMITLINT_CONFIG_FILE_NAMES } from '../constant/commitlint/file-names.constant.js';
import { COMMITLINT_CONFIG_FILE_PATHS } from '../constant/commitlint/file-paths.constant.js';
import { COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT } from '../constant/commitlint/husky-commit-msg-script.constant.js';
import { COMMITLINT_CONFIG_HUSKY } from '../constant/commitlint/husky-config.constant.js';
import { COMMITLINT_CONFIG_MESSAGES } from '../constant/commitlint/messages.constant.js';
import { COMMITLINT_CONFIG_SCRIPTS } from '../constant/commitlint/scripts.constant.js';
import { COMMITLINT_CONFIG_SUMMARY } from '../constant/commitlint/summary.constant.js';
import { PackageJsonService } from './package-json.service.js';
const MAX_RETRY_COUNT = 10;
const MIN_RETRY_COUNT = 1;
/**
* 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;
/** Cached commitlint module configuration */
config = null;
/**
* 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 = [COMMITLINT_CONFIG_MESSAGES.existingFilesDetected];
messageLines.push("");
if (existingFiles.length > 0) {
for (const file of existingFiles) {
messageLines.push(`- ${file}`);
}
}
messageLines.push("", COMMITLINT_CONFIG_MESSAGES.deleteFilesQuestion);
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(COMMITLINT_CONFIG_MESSAGES.existingFilesAborted);
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 {
this.config = await this.CONFIG_SERVICE.getModuleConfig(EModule.COMMITLINT);
if (!(await this.shouldInstall())) {
return { wasInstalled: false };
}
if (!(await this.handleExistingSetup())) {
return { wasInstalled: false };
}
const isCommitCommandEnabled = await this.shouldEnableCommitCommand();
const commitlintAiConfig = await this.resolveCommitlintAiConfig();
await this.setupCommitlint(commitlintAiConfig, isCommitCommandEnabled);
return { wasInstalled: true };
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.failedSetupError, error);
throw error;
}
}
/**
* Reads generation model.
* @param defaultModel - Default model value
* @returns Promise resolving to configured model
*/
async readGenerationModel(defaultModel) {
try {
const model = await this.CLI_INTERFACE_SERVICE.text(COMMITLINT_CONFIG_MESSAGES.modelPrompt, "", defaultModel, (value) => (value.trim().length === 0 ? "Model is required" : undefined));
return model.trim().length > 0 ? model.trim() : defaultModel;
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.modelPromptError, error);
return defaultModel;
}
}
/**
* Reads retry count with range validation.
* @param prompt - Prompt message
* @param errorPrompt - Error message
* @param defaultValue - Default retry value
* @returns Promise resolving to retry count
*/
async readRetryCount(prompt, errorPrompt, defaultValue) {
try {
const value = await this.CLI_INTERFACE_SERVICE.text(prompt, "", String(defaultValue), (retryCount) => {
const parsedValue = Number.parseInt(retryCount, 10);
return Number.isNaN(parsedValue) || parsedValue < MIN_RETRY_COUNT || parsedValue > MAX_RETRY_COUNT ? `Please enter a number between ${MIN_RETRY_COUNT} and ${MAX_RETRY_COUNT}` : undefined;
});
const parsedValue = Number.parseInt(value, 10);
return Number.isNaN(parsedValue) ? defaultValue : parsedValue;
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(errorPrompt, error);
return defaultValue;
}
}
/**
* Reads regex pattern for ticket extraction.
* @param defaultPattern - Default regex pattern
* @returns Promise resolving to configured regex pattern
*/
async readTicketPattern(defaultPattern) {
try {
const pattern = await this.CLI_INTERFACE_SERVICE.text(COMMITLINT_CONFIG_MESSAGES.ticketPatternPrompt, "", defaultPattern);
return pattern.trim().length > 0 ? pattern.trim() : defaultPattern;
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.ticketPatternPromptError, error);
return defaultPattern;
}
}
/**
* Reads regex flags for ticket pattern.
* @param defaultPatternFlags - Default regex flags
* @returns Promise resolving to configured regex flags
*/
async readTicketPatternFlags(defaultPatternFlags) {
try {
const patternFlags = await this.CLI_INTERFACE_SERVICE.text(COMMITLINT_CONFIG_MESSAGES.ticketPatternFlagsPrompt, "", defaultPatternFlags);
return patternFlags.trim().length > 0 ? patternFlags.trim() : defaultPatternFlags;
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.ticketPatternFlagsPromptError, error);
return defaultPatternFlags;
}
}
/**
* Resolves commitlint-ai settings using config defaults and setup prompts.
* @returns Promise resolving to effective commitlint-ai settings
*/
async resolveCommitlintAiConfig() {
const defaultCommitlintAiConfig = this.getDefaultCommitlintAiConfig();
const mode = await this.selectGenerationMode(defaultCommitlintAiConfig.mode ?? COMMITLINT_AI_DEFAULTS.mode);
const provider = await this.selectGenerationProvider(defaultCommitlintAiConfig.provider ?? COMMITLINT_AI_DEFAULTS.provider);
const model = await this.readGenerationModel(this.config?.model ?? this.getDefaultModelByProvider(provider));
const maxRetries = await this.readRetryCount(COMMITLINT_CONFIG_MESSAGES.maxRetriesPrompt, COMMITLINT_CONFIG_MESSAGES.maxRetriesPromptError, defaultCommitlintAiConfig.maxRetries ?? COMMITLINT_AI_DEFAULTS.maxRetries);
const validationMaxRetries = await this.readRetryCount(COMMITLINT_CONFIG_MESSAGES.validationMaxRetriesPrompt, COMMITLINT_CONFIG_MESSAGES.validationMaxRetriesPromptError, defaultCommitlintAiConfig.validationMaxRetries ?? COMMITLINT_AI_DEFAULTS.validationMaxRetries);
const ticketDefaults = {
missingBranchLintBehavior: defaultCommitlintAiConfig.ticket?.missingBranchLintBehavior ?? COMMITLINT_AI_DEFAULTS.ticket.missingBranchLintBehavior,
normalization: defaultCommitlintAiConfig.ticket?.normalization ?? COMMITLINT_AI_DEFAULTS.ticket.normalization,
pattern: defaultCommitlintAiConfig.ticket?.pattern ?? COMMITLINT_AI_DEFAULTS.ticket.pattern,
patternFlags: defaultCommitlintAiConfig.ticket?.patternFlags ?? COMMITLINT_AI_DEFAULTS.ticket.patternFlags,
source: defaultCommitlintAiConfig.ticket?.source ?? COMMITLINT_AI_DEFAULTS.ticket.source,
};
const isTicketEnabled = await this.shouldEnableTicketIntegration(ticketDefaults.source);
if (!isTicketEnabled) {
return {
maxRetries,
mode,
model,
provider,
ticket: {
...ticketDefaults,
source: ECommitlintTicketSource.NONE,
},
validationMaxRetries,
};
}
const ticketSource = await this.selectTicketSource(ticketDefaults.source);
const ticketNormalization = await this.selectTicketNormalization(ticketDefaults.normalization);
let ticketPattern = ticketDefaults.pattern;
let ticketPatternFlags = ticketDefaults.patternFlags;
let ticketMissingBranchLintBehavior = ticketDefaults.missingBranchLintBehavior;
if (ticketSource === ECommitlintTicketSource.AUTO || ticketSource === ECommitlintTicketSource.PATTERN) {
ticketPattern = await this.readTicketPattern(ticketDefaults.pattern);
ticketPatternFlags = await this.readTicketPatternFlags(ticketDefaults.patternFlags);
}
if (ticketSource === ECommitlintTicketSource.BRANCH_LINT) {
ticketMissingBranchLintBehavior = await this.selectMissingBranchLintBehavior(ticketDefaults.missingBranchLintBehavior);
}
return {
maxRetries,
mode,
model,
provider,
ticket: {
missingBranchLintBehavior: ticketMissingBranchLintBehavior,
normalization: ticketNormalization,
pattern: ticketPattern,
patternFlags: ticketPatternFlags,
source: ticketSource,
},
validationMaxRetries,
};
}
/**
* Selects generation mode.
* @param defaultMode - Default mode value
* @returns Promise resolving to selected mode
*/
async selectGenerationMode(defaultMode) {
const options = [
{ label: "auto - AI-powered generation", value: ECommitlintMode.AUTO },
{ label: "manual - guided commit composition", value: ECommitlintMode.MANUAL },
];
try {
return await this.CLI_INTERFACE_SERVICE.select(COMMITLINT_CONFIG_MESSAGES.modePrompt, options, defaultMode);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.modePromptError, error);
return defaultMode;
}
}
/**
* Selects generation provider.
* @param defaultProvider - Default provider value
* @returns Promise resolving to selected provider
*/
async selectGenerationProvider(defaultProvider) {
const options = [
{ label: "anthropic", value: ECommitlintProvider.ANTHROPIC },
{ label: "aws-bedrock", value: ECommitlintProvider.AWS_BEDROCK },
{ label: "azure-openai", value: ECommitlintProvider.AZURE_OPENAI },
{ label: "google", value: ECommitlintProvider.GOOGLE },
{ label: "ollama", value: ECommitlintProvider.OLLAMA },
{ label: "openai", value: ECommitlintProvider.OPENAI },
];
try {
return await this.CLI_INTERFACE_SERVICE.select(COMMITLINT_CONFIG_MESSAGES.providerPrompt, options, defaultProvider);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.providerPromptError, error);
return defaultProvider;
}
}
/**
* Selects missing branch-lint behavior.
* @param defaultBehavior - Default behavior
* @returns Promise resolving to selected behavior
*/
async selectMissingBranchLintBehavior(defaultBehavior) {
const options = [
{ label: "fallback - use local regex pattern as fallback", value: ECommitlintTicketMissingBranchLintBehavior.FALLBACK },
{ label: "error - stop setup when branch-lint config is unavailable", value: ECommitlintTicketMissingBranchLintBehavior.ERROR },
];
try {
return await this.CLI_INTERFACE_SERVICE.select(COMMITLINT_CONFIG_MESSAGES.branchLintMissingBehaviorPrompt, options, defaultBehavior);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.branchLintMissingBehaviorPromptError, error);
return defaultBehavior;
}
}
/**
* Selects ticket normalization mode.
* @param defaultNormalization - Default normalization mode
* @returns Promise resolving to selected normalization mode
*/
async selectTicketNormalization(defaultNormalization) {
const options = [
{ label: "preserve - keep ticket case as detected", value: ECommitlintTicketNormalization.PRESERVE },
{ label: "upper - convert ticket to upper case", value: ECommitlintTicketNormalization.UPPER },
{ label: "lower - convert ticket to lower case", value: ECommitlintTicketNormalization.LOWER },
];
try {
return await this.CLI_INTERFACE_SERVICE.select(COMMITLINT_CONFIG_MESSAGES.ticketNormalizationPrompt, options, defaultNormalization);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.ticketNormalizationPromptError, error);
return defaultNormalization;
}
}
/**
* Selects ticket source strategy.
* @param defaultSource - Default source strategy
* @returns Promise resolving to selected source strategy
*/
async selectTicketSource(defaultSource) {
const options = [
{ label: "branch-lint - parse ticket by git-branch-lint pattern", value: ECommitlintTicketSource.BRANCH_LINT },
{ label: "auto - branch-lint first, then local regex fallback", value: ECommitlintTicketSource.AUTO },
{ label: "pattern - parse ticket only by local regex pattern", value: ECommitlintTicketSource.PATTERN },
];
const normalizedDefaultSource = defaultSource === ECommitlintTicketSource.NONE ? ECommitlintTicketSource.BRANCH_LINT : defaultSource;
try {
return await this.CLI_INTERFACE_SERVICE.select(COMMITLINT_CONFIG_MESSAGES.ticketSourcePrompt, options, normalizedDefaultSource);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.ticketSourcePromptError, error);
return normalizedDefaultSource;
}
}
/**
* Determines whether commit command script should be added.
* @returns Promise resolving to true when commit command should be added
*/
async shouldEnableCommitCommand() {
const isCommitCommandEnabledByDefault = this.config?.isCommitCommandEnabled ?? true;
try {
return await this.CLI_INTERFACE_SERVICE.confirm(COMMITLINT_CONFIG_MESSAGES.commitCommandPrompt, isCommitCommandEnabledByDefault);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.commitCommandPromptError, error);
return isCommitCommandEnabledByDefault;
}
}
/**
* Determines whether ticket extraction should be enabled.
* @param defaultSource - Default ticket source
* @returns Promise resolving to true when ticket extraction should be enabled
*/
async shouldEnableTicketIntegration(defaultSource) {
const isTicketEnabledByDefault = defaultSource !== ECommitlintTicketSource.NONE;
try {
return await this.CLI_INTERFACE_SERVICE.confirm(COMMITLINT_CONFIG_MESSAGES.ticketEnabledPrompt, isTicketEnabledByDefault);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.ticketEnabledPromptError, error);
return isTicketEnabledByDefault;
}
}
/**
* 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(COMMITLINT_CONFIG_MESSAGES.confirmSetup, await this.CONFIG_SERVICE.isModuleEnabled(EModule.COMMITLINT));
}
catch (error) {
this.CLI_INTERFACE_SERVICE.handleError(COMMITLINT_CONFIG_MESSAGES.failedConfirmation, error);
return false;
}
}
/**
* Creates the Commitlint configuration file.
* @param commitlintAiConfig - Commitlint AI configuration
*/
async createConfigs(commitlintAiConfig = this.getDefaultCommitlintAiConfig()) {
await this.FILE_SYSTEM_SERVICE.writeFile(COMMITLINT_CONFIG_FILE_PATHS.configFile, COMMITLINT_CONFIG, "utf8");
await this.FILE_SYSTEM_SERVICE.writeFile(COMMITLINT_CONFIG_FILE_PATHS.aiConfigFile, COMMITLINT_AI_CONFIG.template(commitlintAiConfig), "utf8");
}
/**
* Displays a summary of the setup results.
* @param commitlintAiConfig - Commitlint AI configuration
* @param isCommitCommandEnabled - Whether commit command was enabled
*/
displaySetupSummary(commitlintAiConfig = this.getDefaultCommitlintAiConfig(), isCommitCommandEnabled = true) {
const commitScriptDescription = isCommitCommandEnabled ? COMMITLINT_CONFIG_SUMMARY.commitDescription : COMMITLINT_CONFIG_SUMMARY.commitCommandDisabledDescription;
const generationMode = commitlintAiConfig.mode ?? COMMITLINT_AI_DEFAULTS.mode;
const generationProvider = commitlintAiConfig.provider ?? COMMITLINT_AI_DEFAULTS.provider;
const generationModel = commitlintAiConfig.model ?? COMMITLINT_AI_DEFAULTS.model;
const generationMaxRetries = commitlintAiConfig.maxRetries ?? COMMITLINT_AI_DEFAULTS.maxRetries;
const generationValidationMaxRetries = commitlintAiConfig.validationMaxRetries ?? COMMITLINT_AI_DEFAULTS.validationMaxRetries;
const ticketSource = commitlintAiConfig.ticket?.source ?? COMMITLINT_AI_DEFAULTS.ticket.source;
const ticketNormalization = commitlintAiConfig.ticket?.normalization ?? COMMITLINT_AI_DEFAULTS.ticket.normalization;
const ticketMissingBranchLintBehavior = commitlintAiConfig.ticket?.missingBranchLintBehavior ?? COMMITLINT_AI_DEFAULTS.ticket.missingBranchLintBehavior;
const generationDescription = COMMITLINT_CONFIG_SUMMARY.generationConfigurationDescription.replace("{mode}", generationMode).replace("{provider}", generationProvider).replace("{model}", generationModel).replace("{maxRetries}", String(generationMaxRetries)).replace("{validationMaxRetries}", String(generationValidationMaxRetries));
const ticketDescription = COMMITLINT_CONFIG_SUMMARY.ticketConfigurationDescription.replace("{source}", ticketSource).replace("{normalization}", ticketNormalization).replace("{missingBranchLintBehavior}", ticketMissingBranchLintBehavior);
const summary = [COMMITLINT_CONFIG_MESSAGES.configurationCreated, "", generationDescription, ticketDescription, "", COMMITLINT_CONFIG_MESSAGES.generatedScriptsLabel, commitScriptDescription, "", COMMITLINT_CONFIG_MESSAGES.configurationFilesLabel, COMMITLINT_CONFIG_SUMMARY.configFileDescription, COMMITLINT_CONFIG_SUMMARY.aiConfigFileDescription, COMMITLINT_CONFIG_SUMMARY.huskyCommitMsgDescription, "", COMMITLINT_CONFIG_MESSAGES.huskyGitHooksInfo];
if (isCommitCommandEnabled) {
summary.push(COMMITLINT_CONFIG_MESSAGES.commitizenDescription);
}
this.CLI_INTERFACE_SERVICE.note(COMMITLINT_CONFIG_MESSAGES.setupCompleteTitle, 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(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook)) {
existingFiles.push(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook);
}
return existingFiles;
}
/**
* Builds commitlint-ai config with defaults merged from setup-wizard config.
* @returns Defaulted commitlint-ai config
*/
getDefaultCommitlintAiConfig() {
return {
maxRetries: this.config?.maxRetries ?? COMMITLINT_AI_DEFAULTS.maxRetries,
mode: this.config?.mode ?? COMMITLINT_AI_DEFAULTS.mode,
model: this.config?.model ?? COMMITLINT_AI_DEFAULTS.model,
provider: this.config?.provider ?? COMMITLINT_AI_DEFAULTS.provider,
ticket: {
missingBranchLintBehavior: this.config?.ticket?.missingBranchLintBehavior ?? COMMITLINT_AI_DEFAULTS.ticket.missingBranchLintBehavior,
normalization: this.config?.ticket?.normalization ?? COMMITLINT_AI_DEFAULTS.ticket.normalization,
pattern: this.config?.ticket?.pattern ?? COMMITLINT_AI_DEFAULTS.ticket.pattern,
patternFlags: this.config?.ticket?.patternFlags ?? COMMITLINT_AI_DEFAULTS.ticket.patternFlags,
source: this.config?.ticket?.source ?? COMMITLINT_AI_DEFAULTS.ticket.source,
},
validationMaxRetries: this.config?.validationMaxRetries ?? COMMITLINT_AI_DEFAULTS.validationMaxRetries,
};
}
/**
* Returns default model for selected provider.
* @param provider - Selected provider
* @returns Default model name
*/
getDefaultModelByProvider(provider) {
switch (provider) {
case ECommitlintProvider.ANTHROPIC: {
return "claude-opus-4-5";
}
case ECommitlintProvider.AWS_BEDROCK: {
return "claude-sonnet-4-5";
}
case ECommitlintProvider.AZURE_OPENAI: {
return "gpt-4o";
}
case ECommitlintProvider.GOOGLE: {
return "gemini-2.5-pro-preview-05-06";
}
case ECommitlintProvider.OLLAMA: {
return "llama3";
}
case ECommitlintProvider.OPENAI: {
return "gpt-4o-mini";
}
default: {
return COMMITLINT_AI_DEFAULTS.model;
}
}
}
/**
* Sets up Commitlint and Commitizen.
* Installs dependencies, creates configuration files, and configures git hooks.
* @param commitlintAiConfig - Commitlint AI configuration
* @param isCommitCommandEnabled - Whether commit command should be configured
*/
async setupCommitlint(commitlintAiConfig = this.getDefaultCommitlintAiConfig(), isCommitCommandEnabled = true) {
this.CLI_INTERFACE_SERVICE.startSpinner(COMMITLINT_CONFIG_MESSAGES.settingUpSpinner);
try {
await this.PACKAGE_JSON_SERVICE.installPackages(COMMITLINT_CONFIG_CORE_DEPENDENCIES, "latest", EPackageJsonDependencyType.DEV);
await this.createConfigs(commitlintAiConfig);
await this.setupHusky();
if (isCommitCommandEnabled) {
await this.setupPackageJsonConfigs();
await this.setupScripts();
}
this.CLI_INTERFACE_SERVICE.stopSpinner(COMMITLINT_CONFIG_MESSAGES.configurationCompleted);
this.displaySetupSummary(commitlintAiConfig, isCommitCommandEnabled);
}
catch (error) {
this.CLI_INTERFACE_SERVICE.stopSpinner(COMMITLINT_CONFIG_MESSAGES.failedSetupConfiguration);
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(COMMITLINT_CONFIG_HUSKY.initCommand);
// Add prepare script if it doesn't exist
await this.PACKAGE_JSON_SERVICE.addScript(COMMITLINT_CONFIG_SCRIPTS.prepare.name, COMMITLINT_CONFIG_SCRIPTS.prepare.command);
await this.COMMAND_SERVICE.execute(COMMITLINT_CONFIG_HUSKY.mkdirCommand);
// Create commit-msg hook
await this.FILE_SYSTEM_SERVICE.writeFile(COMMITLINT_CONFIG_FILE_PATHS.huskyCommitMsgHook, COMMITLINT_CONFIG_HUSKY_COMMIT_MSG_SCRIPT, "utf8");
await this.COMMAND_SERVICE.execute(COMMITLINT_CONFIG_HUSKY.chmodCommand);
}
/**
* Sets up Commitizen configuration in package.json.
*/
async setupPackageJsonConfigs() {
const packageJson = await this.PACKAGE_JSON_SERVICE.get();
packageJson.config ??= {};
packageJson.config.commitizen = {
path: COMMITLINT_CONFIG_MESSAGES.commitizenPath,
};
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(COMMITLINT_CONFIG_SCRIPTS.commit.name, COMMITLINT_CONFIG_SCRIPTS.commit.command);
}
}
export { CommitlintModuleService };
//# sourceMappingURL=commitlint-module.service.js.map