Files
cli/ts/mod_config/index.ts

432 lines
13 KiB
TypeScript

// gitzone config - manage release registry configuration
import * as plugins from './mod.plugins.js';
import { ReleaseConfig } from './classes.releaseconfig.js';
import { CommitConfig } from './classes.commitconfig.js';
import { runFormatter, type ICheckResult } from '../mod_format/index.js';
export { ReleaseConfig, CommitConfig };
/**
* Format npmextra.json with diff preview
* Shows diff first, asks for confirmation, then applies
*/
async function formatNpmextraWithDiff(): Promise<void> {
// Check for diffs first
const checkResult = await runFormatter('npmextra', {
checkOnly: true,
showDiff: true,
}) as ICheckResult | void;
if (checkResult && checkResult.hasDiff) {
const shouldApply = await plugins.smartinteract.SmartInteract.getCliConfirmation(
'Apply formatting changes to npmextra.json?',
true
);
if (shouldApply) {
await runFormatter('npmextra', { silent: true });
}
}
}
export const run = async (argvArg: any) => {
const command = argvArg._?.[1];
const value = argvArg._?.[2];
// If no command provided, show interactive menu
if (!command) {
await handleInteractiveMenu();
return;
}
switch (command) {
case 'show':
await handleShow();
break;
case 'add':
await handleAdd(value);
break;
case 'remove':
await handleRemove(value);
break;
case 'clear':
await handleClear();
break;
case 'access':
case 'accessLevel':
await handleAccessLevel(value);
break;
case 'commit':
await handleCommit(argvArg._?.[2], argvArg._?.[3]);
break;
case 'services':
await handleServices();
break;
case 'help':
showHelp();
break;
default:
plugins.logger.log('error', `Unknown command: ${command}`);
showHelp();
}
};
/**
* Interactive menu for config command
*/
async function handleInteractiveMenu(): Promise<void> {
console.log('');
console.log('╭─────────────────────────────────────────────────────────────╮');
console.log('│ gitzone config - Project Configuration │');
console.log('╰─────────────────────────────────────────────────────────────╯');
console.log('');
const interactInstance = new plugins.smartinteract.SmartInteract();
const response = await interactInstance.askQuestion({
type: 'list',
name: 'action',
message: 'What would you like to do?',
default: 'show',
choices: [
{ name: 'Show current configuration', value: 'show' },
{ name: 'Add a registry', value: 'add' },
{ name: 'Remove a registry', value: 'remove' },
{ name: 'Clear all registries', value: 'clear' },
{ name: 'Set access level (public/private)', value: 'access' },
{ name: 'Configure commit options', value: 'commit' },
{ name: 'Configure services', value: 'services' },
{ name: 'Show help', value: 'help' },
],
});
const action = (response as any).value;
switch (action) {
case 'show':
await handleShow();
break;
case 'add':
await handleAdd();
break;
case 'remove':
await handleRemove();
break;
case 'clear':
await handleClear();
break;
case 'access':
await handleAccessLevel();
break;
case 'commit':
await handleCommit();
break;
case 'services':
await handleServices();
break;
case 'help':
showHelp();
break;
}
}
/**
* Show current registry configuration
*/
async function handleShow(): Promise<void> {
const config = await ReleaseConfig.fromCwd();
const registries = config.getRegistries();
const accessLevel = config.getAccessLevel();
console.log('');
console.log('╭─────────────────────────────────────────────────────────────╮');
console.log('│ Release Configuration │');
console.log('╰─────────────────────────────────────────────────────────────╯');
console.log('');
// Show access level
plugins.logger.log('info', `Access Level: ${accessLevel}`);
console.log('');
if (registries.length === 0) {
plugins.logger.log('info', 'No release registries configured.');
console.log('');
console.log(' Run `gitzone config add <registry-url>` to add one.');
console.log('');
} else {
plugins.logger.log('info', `Configured registries (${registries.length}):`);
console.log('');
registries.forEach((url, index) => {
console.log(` ${index + 1}. ${url}`);
});
console.log('');
}
}
/**
* Add a registry URL
*/
async function handleAdd(url?: string): Promise<void> {
if (!url) {
// Interactive mode
const interactInstance = new plugins.smartinteract.SmartInteract();
const response = await interactInstance.askQuestion({
type: 'input',
name: 'registryUrl',
message: 'Enter registry URL:',
default: 'https://registry.npmjs.org',
validate: (input: string) => {
return !!(input && input.trim() !== '');
},
});
url = (response as any).value;
}
const config = await ReleaseConfig.fromCwd();
const added = config.addRegistry(url!);
if (added) {
await config.save();
plugins.logger.log('success', `Added registry: ${url}`);
await formatNpmextraWithDiff();
} else {
plugins.logger.log('warn', `Registry already exists: ${url}`);
}
}
/**
* Remove a registry URL
*/
async function handleRemove(url?: string): Promise<void> {
const config = await ReleaseConfig.fromCwd();
const registries = config.getRegistries();
if (registries.length === 0) {
plugins.logger.log('warn', 'No registries configured to remove.');
return;
}
if (!url) {
// Interactive mode - show list to select from
const interactInstance = new plugins.smartinteract.SmartInteract();
const response = await interactInstance.askQuestion({
type: 'list',
name: 'registryUrl',
message: 'Select registry to remove:',
choices: registries,
default: registries[0],
});
url = (response as any).value;
}
const removed = config.removeRegistry(url!);
if (removed) {
await config.save();
plugins.logger.log('success', `Removed registry: ${url}`);
await formatNpmextraWithDiff();
} else {
plugins.logger.log('warn', `Registry not found: ${url}`);
}
}
/**
* Clear all registries
*/
async function handleClear(): Promise<void> {
const config = await ReleaseConfig.fromCwd();
if (!config.hasRegistries()) {
plugins.logger.log('info', 'No registries to clear.');
return;
}
// Confirm before clearing
const confirmed = await plugins.smartinteract.SmartInteract.getCliConfirmation(
'Clear all configured registries?',
false
);
if (confirmed) {
config.clearRegistries();
await config.save();
plugins.logger.log('success', 'All registries cleared.');
await formatNpmextraWithDiff();
} else {
plugins.logger.log('info', 'Operation cancelled.');
}
}
/**
* Set or toggle access level
*/
async function handleAccessLevel(level?: string): Promise<void> {
const config = await ReleaseConfig.fromCwd();
const currentLevel = config.getAccessLevel();
if (!level) {
// Interactive mode - toggle or ask
const interactInstance = new plugins.smartinteract.SmartInteract();
const response = await interactInstance.askQuestion({
type: 'list',
name: 'accessLevel',
message: 'Select npm access level for publishing:',
choices: ['public', 'private'],
default: currentLevel,
});
level = (response as any).value;
}
// Validate the level
if (level !== 'public' && level !== 'private') {
plugins.logger.log('error', `Invalid access level: ${level}. Must be 'public' or 'private'.`);
return;
}
if (level === currentLevel) {
plugins.logger.log('info', `Access level is already set to: ${level}`);
return;
}
config.setAccessLevel(level as 'public' | 'private');
await config.save();
plugins.logger.log('success', `Access level set to: ${level}`);
await formatNpmextraWithDiff();
}
/**
* Handle commit configuration
*/
async function handleCommit(setting?: string, value?: string): Promise<void> {
const config = await CommitConfig.fromCwd();
// No setting = interactive mode
if (!setting) {
await handleCommitInteractive(config);
return;
}
// Direct setting
switch (setting) {
case 'alwaysTest':
await handleCommitSetting(config, 'alwaysTest', value);
break;
case 'alwaysBuild':
await handleCommitSetting(config, 'alwaysBuild', value);
break;
default:
plugins.logger.log('error', `Unknown commit setting: ${setting}`);
showCommitHelp();
}
}
/**
* Interactive commit configuration
*/
async function handleCommitInteractive(config: CommitConfig): Promise<void> {
console.log('');
console.log('╭─────────────────────────────────────────────────────────────╮');
console.log('│ Commit Configuration │');
console.log('╰─────────────────────────────────────────────────────────────╯');
console.log('');
const interactInstance = new plugins.smartinteract.SmartInteract();
const response = await interactInstance.askQuestion({
type: 'checkbox',
name: 'commitOptions',
message: 'Select commit options to enable:',
choices: [
{ name: 'Always run tests before commit (-t)', value: 'alwaysTest' },
{ name: 'Always build after commit (-b)', value: 'alwaysBuild' },
],
default: [
...(config.getAlwaysTest() ? ['alwaysTest'] : []),
...(config.getAlwaysBuild() ? ['alwaysBuild'] : []),
],
});
const selected = (response as any).value || [];
config.setAlwaysTest(selected.includes('alwaysTest'));
config.setAlwaysBuild(selected.includes('alwaysBuild'));
await config.save();
plugins.logger.log('success', 'Commit configuration updated');
await formatNpmextraWithDiff();
}
/**
* Set a specific commit setting
*/
async function handleCommitSetting(config: CommitConfig, setting: string, value?: string): Promise<void> {
// Parse boolean value
const boolValue = value === 'true' || value === '1' || value === 'on';
if (setting === 'alwaysTest') {
config.setAlwaysTest(boolValue);
} else if (setting === 'alwaysBuild') {
config.setAlwaysBuild(boolValue);
}
await config.save();
plugins.logger.log('success', `Set ${setting} to ${boolValue}`);
await formatNpmextraWithDiff();
}
/**
* Show help for commit subcommand
*/
function showCommitHelp(): void {
console.log('');
console.log('Usage: gitzone config commit [setting] [value]');
console.log('');
console.log('Settings:');
console.log(' alwaysTest [true|false] Always run tests before commit');
console.log(' alwaysBuild [true|false] Always build after commit');
console.log('');
console.log('Examples:');
console.log(' gitzone config commit # Interactive mode');
console.log(' gitzone config commit alwaysTest true');
console.log(' gitzone config commit alwaysBuild false');
console.log('');
}
/**
* Handle services configuration
*/
async function handleServices(): Promise<void> {
// Import and use ServiceManager's configureServices
const { ServiceManager } = await import('../mod_services/classes.servicemanager.js');
const serviceManager = new ServiceManager();
await serviceManager.init();
await serviceManager.configureServices();
}
/**
* Show help for config command
*/
function showHelp(): void {
console.log('');
console.log('Usage: gitzone config <command> [options]');
console.log('');
console.log('Commands:');
console.log(' show Display current release configuration');
console.log(' add [url] Add a registry URL');
console.log(' remove [url] Remove a registry URL');
console.log(' clear Clear all registries');
console.log(' access [public|private] Set npm access level for publishing');
console.log(' commit [setting] [value] Configure commit options');
console.log(' services Configure which services are enabled');
console.log('');
console.log('Examples:');
console.log(' gitzone config show');
console.log(' gitzone config add https://registry.npmjs.org');
console.log(' gitzone config add https://verdaccio.example.com');
console.log(' gitzone config remove https://registry.npmjs.org');
console.log(' gitzone config clear');
console.log(' gitzone config access public');
console.log(' gitzone config access private');
console.log(' gitzone config commit # Interactive');
console.log(' gitzone config commit alwaysTest true');
console.log(' gitzone config services # Interactive');
console.log('');
}