UNPKG

gitset

Version:

Enhanced git init with user configuration management

221 lines 9.45 kB
import { GitDetector } from './git-detector.js'; import { ConfigManager } from './config-manager.js'; import { GitInstaller } from './git-installer.js'; import { WelcomeScreen } from '../ui/welcome.js'; import { UserPrompts } from '../ui/prompts.js'; import { ErrorHandler } from '../utils/error-handler.js'; import { ErrorType } from '../types/cli.js'; import { CLI_CONFIG, MESSAGES } from '../config/constants.js'; /** * Orchestrates the main workflow of git repository initialization * Separates business logic from CLI concerns for better testability */ export class WorkflowOrchestrator { gitDetector; configManager; gitInstaller; welcomeScreen; userPrompts; constructor(gitDetector, configManager, gitInstaller, welcomeScreen, userPrompts) { this.gitDetector = gitDetector; this.configManager = configManager; this.gitInstaller = gitInstaller; this.welcomeScreen = welcomeScreen; this.userPrompts = userPrompts; } /** * Execute the complete gitset workflow */ async execute(directory, options) { try { // Step 1: Welcome user await this.welcomeScreen.show(); // Step 2: Ensure Git is available await this.ensureGitInstallation(); // Step 3: Get directory path from user const targetDirectory = await this.getTargetDirectory(directory); // Step 4: Check if Git repository already exists and handle accordingly const shouldContinue = await this.checkExistingGitRepo(targetDirectory); if (!shouldContinue) { this.userPrompts.showExitMessage(); return { success: false, directory: targetDirectory, userInfo: { name: '', email: '', source: 'user-input' }, errors: ['User cancelled initialization'], warnings: [] }; } // Step 5: Get user configuration const userInfo = await this.getUserConfiguration(options.global); // Step 6: Ensure directory exists await this.ensureDirectoryExists(targetDirectory); // Step 7: Initialize repository const result = await this.initializeRepository(targetDirectory, userInfo); // Step 8: Show results await this.showResults(result); return result; } catch (error) { throw ErrorHandler.createError(ErrorType.CONFIG_ERROR, `Workflow execution failed: ${error}`, true, 'Check your configuration and try again'); } } /** * Ensure Git is installed on the system */ async ensureGitInstallation() { const gitStatus = await this.gitDetector.checkInstallation(); if (!gitStatus.installed) { if (!gitStatus.canAutoInstall) { throw ErrorHandler.createError(ErrorType.GIT_NOT_FOUND, 'Git is not installed and cannot be automatically installed', false, 'Please install Git manually from https://git-scm.com/downloads'); } const shouldInstall = await this.userPrompts.promptGitInstallation(); if (!shouldInstall) { throw ErrorHandler.createError(ErrorType.GIT_NOT_FOUND, MESSAGES.error.gitRequired, false); } await this.installGit(); } } /** * Install Git using available methods */ async installGit() { const methods = await this.gitInstaller.getAvailableInstallationMethods(); if (methods.length === 0) { throw ErrorHandler.createError(ErrorType.INSTALLATION_FAILED, 'No installation methods available', false, 'Please install Git manually'); } const selectedMethod = methods.length === 1 ? methods[0] : await this.selectInstallationMethod(methods); const success = await this.gitInstaller.installGit(selectedMethod); if (!success) { throw ErrorHandler.createError(ErrorType.INSTALLATION_FAILED, `Git installation failed using ${selectedMethod.name}`, true, 'Try a different installation method or install manually'); } } /** * Select installation method when multiple options are available */ async selectInstallationMethod(methods) { const methodNames = methods.map(m => m.name); const selectedName = await this.userPrompts.selectInstallationMethod(methodNames); return methods.find(m => m.name === selectedName) || methods[0]; } /** * Validate directory with retry logic */ async validateAndGetDirectory(initialDirectory) { let directory = initialDirectory; let attempts = 0; while (attempts < CLI_CONFIG.maxValidationAttempts) { const validation = await this.configManager.validateDirectory(directory); if (validation.valid) { return directory; } this.welcomeScreen.showError(MESSAGES.error.validationFailed, validation.errors.join(', ')); attempts++; if (attempts >= CLI_CONFIG.maxValidationAttempts) { throw ErrorHandler.createError(ErrorType.VALIDATION_ERROR, MESSAGES.error.maxAttemptsExceeded, false); } directory = await this.userPrompts.promptDirectory(directory); } return directory; } /** * Get user configuration based on options */ async getUserConfiguration(useGlobal) { if (useGlobal) { return await this.gitDetector.getGlobalConfig(); } const globalConfig = await this.gitDetector.getGlobalConfig(); return await this.userPrompts.promptUserInfo(globalConfig); } /** * Initialize Git repository */ async initializeRepository(directory, userInfo) { return await ErrorHandler.safeExecute(() => this.configManager.initializeRepository(directory, userInfo), ErrorType.CONFIG_ERROR, 'Failed to initialize Git repository', 'Check directory permissions and try again'); } /** * Show workflow results to user */ async showResults(result) { if (result.success) { // Check if this was a config update (warnings indicate existing repo) const isConfigUpdate = result.warnings && result.warnings.length > 0 && result.warnings.some(w => w.includes('already exists')); this.welcomeScreen.showSuccess(result.directory, result.userInfo, isConfigUpdate); } else { const errorMessage = result.errors?.join(', ') || 'Unknown error'; this.welcomeScreen.showError(MESSAGES.error.gitInitFailed, errorMessage); throw ErrorHandler.createError(ErrorType.CONFIG_ERROR, errorMessage, true, 'Check the error details and try again'); } } /** * Legacy methods for backward compatibility with CLI tests * These delegate to the appropriate components */ async checkGitInstallation() { return await this.gitDetector.checkInstallation(); } async getGlobalGitConfig() { return await this.gitDetector.getGlobalConfig(); } async validateDirectory(directory) { return await this.configManager.validateDirectory(directory); } async initializeGitRepository(directory, userInfo) { return await this.configManager.initializeRepository(directory, userInfo); } /** * Get target directory from user input */ async getTargetDirectory(initialDirectory) { // If directory is provided via CLI args and it's not the default, use it if (initialDirectory && initialDirectory !== CLI_CONFIG.defaultDirectory) { return initialDirectory; } // Otherwise, prompt user for directory return await this.userPrompts.promptDirectory(); } /** * Check if Git repository already exists and handle user decision */ async checkExistingGitRepo(directory) { const hasGit = await this.configManager.hasGitDirectory(directory); if (hasGit) { return await this.userPrompts.promptGitRepoReinitialize(); } return true; } /** * Ensure target directory exists (create if needed) */ async ensureDirectoryExists(directory) { try { await this.configManager.validateDirectory(directory); // Use ValidationUtils to create directory if needed const path = await import('path'); const fs = await import('fs/promises'); const resolvedPath = path.resolve(directory); try { await fs.stat(resolvedPath); } catch { // Directory doesn't exist, create it await fs.mkdir(resolvedPath, { recursive: true }); } } catch (error) { throw ErrorHandler.createError(ErrorType.VALIDATION_ERROR, `Failed to ensure directory exists: ${error}`, true, 'Check directory permissions and path'); } } /** * Factory method to create orchestrator with default dependencies */ static createDefault() { return new WorkflowOrchestrator(new GitDetector(), new ConfigManager(), new GitInstaller(), new WelcomeScreen(), new UserPrompts()); } } //# sourceMappingURL=workflow-orchestrator.js.map