@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
393 lines (392 loc) • 15.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addGitSubmodule = addGitSubmodule;
exports.removeGitSubmodule = removeGitSubmodule;
exports.updateGitSubmodules = updateGitSubmodules;
exports.showSubmoduleStatus = showSubmoduleStatus;
exports.initSubmodules = initSubmodules;
exports.manageSubmodules = manageSubmodules;
const chalk_1 = __importDefault(require("chalk"));
const prompts_1 = __importDefault(require("prompts"));
const submodule_1 = require("../utils/submodule");
const monorepo_1 = require("../utils/monorepo");
/**
* Add a new Git submodule
*/
async function addGitSubmodule(repositoryUrl, options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Checking Git repository...');
}
// Ensure we're in a Git repository
if (!(await (0, submodule_1.isGitRepository)())) {
throw new Error('Not in a Git repository. Initialize Git first with: git init');
}
if (spinner) {
spinner.stop();
}
// Interactive prompts for missing options
const responses = await (0, prompts_1.default)([
{
type: options.path ? null : 'text',
name: 'path',
message: 'Submodule path:',
initial: repositoryUrl.split('/').pop()?.replace('.git', '') || 'submodule',
validate: (value) => (value.trim() ? true : 'Path is required'),
},
{
type: options.branch ? null : 'text',
name: 'branch',
message: 'Branch to track:',
initial: 'main',
},
]);
const finalOptions = {
path: options.path || responses.path,
branch: options.branch || responses.branch || 'main',
};
if (spinner) {
spinner.start();
spinner.setText(`Adding submodule: ${repositoryUrl}`);
}
console.log(chalk_1.default.cyan(`Adding submodule: ${repositoryUrl}`));
console.log(chalk_1.default.gray(`Path: ${finalOptions.path}`));
console.log(chalk_1.default.gray(`Branch: ${finalOptions.branch}`));
await (0, submodule_1.addSubmodule)(finalOptions.path, repositoryUrl, finalOptions.branch);
if (spinner) {
spinner.setText('Updating documentation...');
}
// Update documentation
const submodules = await (0, submodule_1.getSubmoduleStatus)();
const monorepoRoot = (await (0, monorepo_1.findMonorepoRoot)()) || process.cwd();
await (0, submodule_1.createSubmoduleDocumentation)(monorepoRoot, submodules);
if (spinner) {
spinner.succeed(chalk_1.default.green(`✓ Submodule added successfully: ${finalOptions.path}`));
}
else {
console.log(chalk_1.default.green(`✓ Submodule added successfully: ${finalOptions.path}`));
}
console.log(chalk_1.default.gray('Documentation updated in docs/SUBMODULES.md'));
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error adding submodule'));
}
console.error(chalk_1.default.red('Error adding submodule:'), error);
throw error;
}
}
/**
* Remove a Git submodule
*/
async function removeGitSubmodule(submodulePath, options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Checking Git repository...');
}
// Ensure we're in a Git repository
if (!(await (0, submodule_1.isGitRepository)())) {
throw new Error('Not in a Git repository.');
}
if (spinner) {
spinner.setText('Loading submodule information...');
}
// Get current submodules to validate path
const submodules = await (0, submodule_1.getSubmoduleStatus)();
const submodule = submodules.find(sub => sub.path === submodulePath || sub.name === submodulePath);
if (!submodule) {
throw new Error(`Submodule not found: ${submodulePath}`);
}
if (spinner) {
spinner.stop();
}
// Confirmation prompt unless force option is used
if (!options.force) {
const { confirm } = await (0, prompts_1.default)({
type: 'confirm',
name: 'confirm',
message: `Are you sure you want to remove submodule "${submodule.path}"?`,
initial: false,
});
if (!confirm) {
console.log(chalk_1.default.yellow('Operation cancelled.'));
return;
}
}
if (spinner) {
spinner.start();
spinner.setText(`Removing submodule: ${submodule.path}`);
}
console.log(chalk_1.default.cyan(`Removing submodule: ${submodule.path}`));
await (0, submodule_1.removeSubmodule)(submodule.path);
if (spinner) {
spinner.setText('Updating documentation...');
}
// Update documentation
const updatedSubmodules = await (0, submodule_1.getSubmoduleStatus)();
const monorepoRoot = (await (0, monorepo_1.findMonorepoRoot)()) || process.cwd();
await (0, submodule_1.createSubmoduleDocumentation)(monorepoRoot, updatedSubmodules);
if (spinner) {
spinner.succeed(chalk_1.default.green(`✓ Submodule removed successfully: ${submodule.path}`));
}
else {
console.log(chalk_1.default.green(`✓ Submodule removed successfully: ${submodule.path}`));
}
console.log(chalk_1.default.gray('Documentation updated in docs/SUBMODULES.md'));
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error removing submodule'));
}
console.error(chalk_1.default.red('Error removing submodule:'), error);
throw error;
}
}
/**
* Update Git submodules
*/
async function updateGitSubmodules(options = {}) {
const { spinner } = options;
try {
if (spinner) {
spinner.setText('Checking Git repository...');
}
// Ensure we're in a Git repository
if (!(await (0, submodule_1.isGitRepository)())) {
throw new Error('Not in a Git repository.');
}
if (options.path) {
if (spinner) {
spinner.setText(`Updating submodule: ${options.path}`);
}
console.log(chalk_1.default.cyan(`Updating submodule: ${options.path}`));
await (0, submodule_1.updateSubmodules)(options.path);
if (spinner) {
spinner.succeed(chalk_1.default.green(`✓ Submodule updated: ${options.path}`));
}
else {
console.log(chalk_1.default.green(`✓ Submodule updated: ${options.path}`));
}
}
else {
if (spinner) {
spinner.setText('Updating all submodules...');
}
console.log(chalk_1.default.cyan('Updating all submodules...'));
await (0, submodule_1.updateSubmodules)();
if (spinner) {
spinner.succeed(chalk_1.default.green('✓ All submodules updated'));
}
else {
console.log(chalk_1.default.green('✓ All submodules updated'));
}
}
if (spinner) {
spinner.setText('Updating documentation...');
}
// Update documentation
const submodules = await (0, submodule_1.getSubmoduleStatus)();
const monorepoRoot = (await (0, monorepo_1.findMonorepoRoot)()) || process.cwd();
await (0, submodule_1.createSubmoduleDocumentation)(monorepoRoot, submodules);
}
catch (error) {
if (spinner) {
spinner.fail(chalk_1.default.red('Error updating submodules'));
}
console.error(chalk_1.default.red('Error updating submodules:'), error);
throw error;
}
}
/**
* Show Git submodule status
*/
async function showSubmoduleStatus() {
try {
// Ensure we're in a Git repository with timeout
const isGitRepo = await Promise.race([
(0, submodule_1.isGitRepository)(),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout checking Git repository')), 3000)),
]);
if (!isGitRepo) {
throw new Error('Not in a Git repository.');
}
const submodules = await Promise.race([
(0, submodule_1.getSubmoduleStatus)(),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout getting submodule status')), 5000)),
]);
if (submodules.length === 0) {
console.log(chalk_1.default.yellow('No submodules found.'));
return;
}
console.log(chalk_1.default.cyan('\n📁 Submodule Status\n'));
submodules.forEach((submodule) => {
const statusColor = getStatusColor(submodule.status);
const statusIcon = getStatusIcon(submodule.status);
console.log(`${statusIcon} ${chalk_1.default.bold(submodule.name)} ${statusColor(submodule.status)}`);
console.log(` ${chalk_1.default.gray('Path:')} ${submodule.path}`);
console.log(` ${chalk_1.default.gray('URL:')} ${submodule.url}`);
console.log(` ${chalk_1.default.gray('Branch:')} ${submodule.branch}`);
console.log(` ${chalk_1.default.gray('Commit:')} ${submodule.commit}`);
console.log();
});
console.log(chalk_1.default.gray(`Total: ${submodules.length} submodules`));
// Show summary by status
const statusCounts = submodules.reduce((acc, sub) => {
acc[sub.status] = (acc[sub.status] || 0) + 1;
return acc;
}, {});
if (Object.keys(statusCounts).length > 1) {
console.log(chalk_1.default.gray('\nStatus Summary:'));
Object.entries(statusCounts).forEach(([status, count]) => {
const color = getStatusColor(status);
console.log(` ${color(status)}: ${count}`);
});
}
}
catch (error) {
console.error(chalk_1.default.red('Error getting submodule status:'), error);
throw error;
}
}
/**
* Initialize submodules (for new clones)
*/
async function initSubmodules() {
try {
// Ensure we're in a Git repository
if (!(await (0, submodule_1.isGitRepository)())) {
throw new Error('Not in a Git repository.');
}
console.log(chalk_1.default.cyan('Initializing submodules...'));
await (0, submodule_1.updateSubmodules)(); // This will init and update
console.log(chalk_1.default.green('✓ Submodules initialized'));
}
catch (error) {
console.error(chalk_1.default.red('Error initializing submodules:'), error);
throw error;
}
}
/**
* Interactive submodule management
*/
async function manageSubmodules() {
try {
// Ensure we're in a Git repository
if (!(await (0, submodule_1.isGitRepository)())) {
throw new Error('Not in a Git repository.');
}
const { action } = await (0, prompts_1.default)({
type: 'select',
name: 'action',
message: 'What would you like to do?',
choices: [
{ title: 'Show status', value: 'status' },
{ title: 'Add submodule', value: 'add' },
{ title: 'Update submodules', value: 'update' },
{ title: 'Remove submodule', value: 'remove' },
{ title: 'Initialize submodules', value: 'init' },
],
});
switch (action) {
case 'status':
await showSubmoduleStatus();
break;
case 'add': {
const { url } = await (0, prompts_1.default)({
type: 'text',
name: 'url',
message: 'Repository URL:',
validate: (value) => (value.trim() ? true : 'URL is required'),
});
await addGitSubmodule(url);
break;
}
case 'update': {
const submodules = await (0, submodule_1.getSubmoduleStatus)();
if (submodules.length === 0) {
console.log(chalk_1.default.yellow('No submodules to update.'));
return;
}
const { updateTarget } = await (0, prompts_1.default)({
type: 'select',
name: 'updateTarget',
message: 'What to update?',
choices: [
{ title: 'All submodules', value: 'all' },
...submodules.map((sub) => ({ title: sub.path, value: sub.path })),
],
});
if (updateTarget === 'all') {
await updateGitSubmodules();
}
else {
await updateGitSubmodules({ path: updateTarget });
}
break;
}
case 'remove': {
const currentSubmodules = await (0, submodule_1.getSubmoduleStatus)();
if (currentSubmodules.length === 0) {
console.log(chalk_1.default.yellow('No submodules to remove.'));
return;
}
const { removeTarget } = await (0, prompts_1.default)({
type: 'select',
name: 'removeTarget',
message: 'Which submodule to remove?',
choices: currentSubmodules.map((sub) => ({
title: sub.path,
value: sub.path,
})),
});
await removeGitSubmodule(removeTarget);
break;
}
case 'init': {
await initSubmodules();
break;
}
}
}
catch (error) {
console.error(chalk_1.default.red('Error managing submodules:'), error);
throw error;
}
}
function getStatusColor(status) {
switch (status) {
case 'clean':
return chalk_1.default.green;
case 'modified':
return chalk_1.default.yellow;
case 'untracked':
return chalk_1.default.red;
case 'ahead':
return chalk_1.default.blue;
case 'behind':
return chalk_1.default.magenta;
default:
return chalk_1.default.gray;
}
}
function getStatusIcon(status) {
switch (status) {
case 'clean':
return chalk_1.default.green('✓');
case 'modified':
return chalk_1.default.yellow('●');
case 'untracked':
return chalk_1.default.red('✗');
case 'ahead':
return chalk_1.default.blue('↑');
case 'behind':
return chalk_1.default.magenta('↓');
default:
return chalk_1.default.gray('?');
}
}