UNPKG

remcode

Version:

Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.

177 lines (176 loc) 7.46 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SetupInitializer = void 0; const logger_1 = require("../utils/logger"); const detector_1 = require("./detector"); const prerequisites_1 = require("./prerequisites"); const secrets_1 = require("./secrets"); const workflow_generator_1 = require("./workflow-generator"); const remcode_config_1 = require("./remcode-config"); const logger = (0, logger_1.getLogger)('SetupInitializer'); /** * Class for initializing Remcode in a repository */ class SetupInitializer { /** * Constructor * @param repoPath Path to the repository * @param githubToken GitHub API token */ constructor(repoPath = process.cwd(), githubToken) { this.repoPath = repoPath; this.detector = new detector_1.SetupDetector(repoPath); this.prerequisites = new prerequisites_1.Prerequisites(repoPath); this.secretsManager = new secrets_1.SecretsManager(githubToken); this.workflowGenerator = new workflow_generator_1.WorkflowGenerator(repoPath); this.configManager = new remcode_config_1.RemcodeConfigManager(repoPath); logger.debug(`SetupInitializer initialized for path: ${repoPath}`); } /** * Initialize a repository with Remcode * @param options Setup options * @returns Setup result */ async initializeRepository(options) { const startTime = Date.now(); const { owner, repo, forceUpdate = false } = options; logger.info(`Initializing remcode for ${owner}/${repo}`); try { // Phase 0: Detect current setup status const setupStatus = await this.detector.detectSetupNeeds(); // If setup is already complete and not forcing update, return early if (!setupStatus.needsSetup && !forceUpdate) { logger.info('Repository already set up, no changes needed'); return { success: true, setupStatus, duration: Date.now() - startTime }; } // Phase 1: Check prerequisites logger.info('Phase 1: Checking prerequisites'); const prerequisiteChecks = await this.prerequisites.checkAll(); const prerequisitesPass = prerequisiteChecks.every((check) => check.passed); if (!prerequisitesPass) { const failedChecks = prerequisiteChecks.filter((check) => !check.passed); const errors = failedChecks.map((check) => check.message).join(', '); throw new Error(`Prerequisites check failed: ${errors}`); } // Use Git info from detector if available const gitInfo = setupStatus.gitInfo; const defaultBranch = options.defaultBranch || gitInfo?.defaultBranch || 'main'; // Phase 2: Configure repository secrets (if not skipped) let secretsResult; if (!options.skipSecrets) { logger.info('Phase 2: Configuring repository secrets'); secretsResult = await this.secretsManager.configureRepositorySecrets(owner, repo); if (secretsResult.failed > 0 && secretsResult.results.some(r => !r.success && r.secretName.includes('REQUIRED'))) { throw new Error('Failed to configure required secrets'); } } else { logger.info('Phase 2: Skipping repository secrets configuration'); } // Phase 3: Generate workflow (if not skipped) let workflowResult; if (!options.skipWorkflow) { logger.info('Phase 3: Generating GitHub Actions workflow'); const workflowOptions = { repoName: repo, owner, branches: [defaultBranch], customSecrets: options.customSecrets }; workflowResult = await this.workflowGenerator.generateWorkflow(workflowOptions, options.workflowType || workflow_generator_1.WorkflowTemplateType.BASIC); if (!workflowResult.success) { throw new Error(`Failed to generate workflow: ${workflowResult.error}`); } } else { logger.info('Phase 3: Skipping workflow generation'); } // Phase 4: Create or update .remcode configuration logger.info('Phase 4: Creating .remcode configuration'); const configOptions = { repository: { name: repo, owner, url: `https://github.com/${owner}/${repo}`, defaultBranch } }; const configResult = await this.configManager.createInitialConfig(owner, repo, configOptions); // Final phase: Update setup status const updatedStatus = await this.detector.detectSetupNeeds(); logger.info('Repository initialization complete'); return { success: true, setupStatus: updatedStatus, prerequisites: prerequisiteChecks, secretsResult, workflowResult, configResult, duration: Date.now() - startTime }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Repository initialization failed: ${errorMessage}`); const finalStatus = await this.detector.detectSetupNeeds().catch(() => ({ needsSetup: true, hasRemcodeFile: false, hasGitRepo: false, hasGitHubRepo: false, hasWorkflow: false, hasRequiredSecrets: false, hasValidConfig: false, reason: detector_1.SetupReason.NO_GITHUB_REPO, detectionTimestamp: new Date().toISOString() })); return { success: false, setupStatus: finalStatus, error: errorMessage, duration: Date.now() - startTime }; } } /** * Check if a repository needs setup * @returns Setup status */ async checkSetupNeeds() { return this.detector.detectSetupNeeds(); } /** * Update an existing Remcode setup * @param options Setup options * @returns Setup result */ async updateSetup(options) { // Force update return this.initializeRepository({ ...options, forceUpdate: true }); } /** * Clean up Remcode setup * @returns True if cleanup was successful */ async cleanupSetup() { try { // Delete configuration file const configDeleted = this.configManager.deleteConfig(); // Could also remove workflow and secrets, but that's potentially destructive // so we'll leave that for manual cleanup return configDeleted; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Cleanup failed: ${errorMessage}`); return false; } } } exports.SetupInitializer = SetupInitializer;