gitset
Version:
Enhanced git init with user configuration management
221 lines • 9.45 kB
JavaScript
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