Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 78 additions & 43 deletions src/content-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import semverSatisfies = require("semver/functions/satisfies");
import { Command } from "commander";
import { Configurator, ModuleHandler } from "./core/command/module-handler";
import { Configurator, IModuleConstructor, ModuleHandler } from "./core/command/module-handler";
import { Context } from "./core/command/cli-context";
import { VersionUtils } from "./core/utils/version";
import { logger } from "./core/utils/logger";
Expand All @@ -14,74 +14,109 @@ import { ContentCLIHelp } from "./core/command/CustomHelp";
* This is the main entry point for the CLI.
*/

// Check if the Node.js version satisfies the minimum requirements
const requiredVersion = ">=10.10.0";
if (!semverSatisfies(process.version, requiredVersion)) {
logger.error(
`Node version ${process.version} not supported. Please upgrade your node version to ${requiredVersion}`
);
process.exit(1);
}

// Global configuration options
const program: Command = new Command();
program.configureHelp({
formatHelp: (cmd, helper) => new ContentCLIHelp().formatHelp(cmd, helper),
subcommandTerm:cmd => new ContentCLIHelp().subcommandTerm(cmd),
optionTerm: opt => new ContentCLIHelp().optionTerm(opt),
});
program.version(VersionUtils.getCurrentCliVersion());
program.option("-q, --quietmode", "Reduce output to a minimum", false);
program.option("-p, --profile [profile]");
program.option("--gitProfile [gitProfile]", "Git profile to use");
program.option("--debug", "Print debug messages", false);
program.option("--dev", "Development Mode", false);
program.parseOptions(process.argv);

if (!program.opts().quietmode) {
console.log(`Content CLI - (C) Copyright 2025 - Celonis SE - Version ${VersionUtils.getCurrentCliVersion()}`);
console.log();
export interface CreateProgramOptions {
/**
* Explicit list of module classes to register. When provided, the factory
* skips automatic, filesystem-based module discovery.
*/
modules?: IModuleConstructor[];
devMode?: boolean;
}

if (program.opts().debug) {
logger.transports.forEach(t => {
t.level = "debug";
/**
* Build a fully-configured Commander program without parsing argv
*/
export function createProgram(context: Context, opts: CreateProgramOptions = {}): Command {
const program = new Command();
program.configureHelp({
formatHelp: (cmd, helper) => new ContentCLIHelp().formatHelp(cmd, helper),
subcommandTerm: cmd => new ContentCLIHelp().subcommandTerm(cmd),
optionTerm: opt => new ContentCLIHelp().optionTerm(opt),
});
program.version(VersionUtils.getCurrentCliVersion());
program.option("-q, --quietmode", "Reduce output to a minimum", false);
program.option("-p, --profile [profile]");
program.option("--gitProfile [gitProfile]", "Git profile to use");
program.option("--debug", "Print debug messages", false);
program.option("--dev", "Development Mode", false);

const moduleHandler = new ModuleHandler(program, context);
configureRootCommands(moduleHandler.configurator);

if (opts.modules) {
for (const moduleClass of opts.modules) {
const moduleInstance = new moduleClass();
moduleInstance.register(context, moduleHandler.configurator);
}
} else {
const rootPath = __dirname;
const devMode = opts.devMode ?? !!program.opts().dev;
moduleHandler.discoverAndRegisterModules(rootPath, devMode);
}

return program;
}

/**
/**
* To support the legacy command structure, we have to configure some root commands
* that the individual modules will extend.
*/
*/
function configureRootCommands(configurator: Configurator): void {
configurator.command("list")
.description("Commands to list content.")
.alias("ls");
configurator.command("list").description("Commands to list content.").alias("ls");
}

async function run(): Promise<void> {
const context = new Context(program.opts());
await context.init();
if (!semverSatisfies(process.version, requiredVersion)) {
logger.error(
`Node version ${process.version} not supported. Please upgrade your node version to ${requiredVersion}`
);
process.exit(1);
}

const moduleHandler = new ModuleHandler(program, context);
// Parse global options up-front so banner/debug-level decisions can use
// them before module discovery runs.
const bootstrapProgram = new Command();
bootstrapProgram.option("-q, --quietmode", "Reduce output to a minimum", false);
bootstrapProgram.option("-p, --profile [profile]");
bootstrapProgram.option("--gitProfile [gitProfile]", "Git profile to use");
bootstrapProgram.option("--debug", "Print debug messages", false);
bootstrapProgram.option("--dev", "Development Mode", false);
bootstrapProgram.allowUnknownOption(true);
bootstrapProgram.parseOptions(process.argv);
const globalOpts = bootstrapProgram.opts();

configureRootCommands(moduleHandler.configurator);
if (!globalOpts.quietmode) {
console.log(`Content CLI - (C) Copyright 2025 - Celonis SE - Version ${VersionUtils.getCurrentCliVersion()}`);
console.log();
}

moduleHandler.discoverAndRegisterModules(__dirname, program.opts().dev);
if (globalOpts.debug) {
logger.transports.forEach(t => {
t.level = "debug";
});
}

const context = new Context(globalOpts);
await context.init();

const program = createProgram(context, { devMode: !!globalOpts.dev });

try {
program.parse(process.argv);
await program.parseAsync(process.argv);
} catch (error) {
logger.error(`An unexpected error occurred: ${error}`);
}
}

run();
if (require.main === module) {
run();
}

// catch uncaught exceptions
process.on("uncaughtException", (error: Error, origin: NodeJS.UncaughtExceptionOrigin) => {
console.error("\n💥 UNCAUGHT EXCEPTION!\n");
console.error("Error:", error);
console.error("Origin:", origin);
process.exit(1);
});
});
149 changes: 0 additions & 149 deletions tests/commands/asset-registry/asset-registry-module.spec.ts

This file was deleted.

Loading
Loading