diff --git a/src/cli.ts b/src/cli.ts index d44f69c..d69f530 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,9 +5,10 @@ import { packageJSON } from './packageJSON.js' import { CreateBirthCommand } from './commands/create/birth.js' import { CheckCommand } from './commands/check.js' import { HelpCommand } from './commands/help.js' +import { InfoCommand } from './commands/info.js' import { KillCommand } from './commands/kill.js' +import { RunCommand } from './commands/run.js' import { StartCommand } from './commands/start.js' -import { InfoCommand } from './commands/info.js' import { UpdateCommand } from './commands/update.js' export const cli = new Cli({ @@ -22,5 +23,6 @@ cli.register(CheckCommand) cli.register(HelpCommand) cli.register(InfoCommand) cli.register(KillCommand) +cli.register(RunCommand) cli.register(StartCommand) cli.register(UpdateCommand) diff --git a/src/commands/__test__/run.test.ts b/src/commands/__test__/run.test.ts new file mode 100644 index 0000000..2b0b7c7 --- /dev/null +++ b/src/commands/__test__/run.test.ts @@ -0,0 +1,9 @@ +import { cli } from '../../cli.js' +import { RunCommand } from '../run.js' + +describe('leon run', () => { + it('should be instance of the command', () => { + const command = cli.process(['run']) + expect(command).toBeInstanceOf(RunCommand) + }) +}) diff --git a/src/commands/check.ts b/src/commands/check.ts index b67d2e6..39fd42b 100644 --- a/src/commands/check.ts +++ b/src/commands/check.ts @@ -14,6 +14,10 @@ export class CheckCommand extends Command { description: 'Name of the Leon instance.' }) + static async run(leonInstance: LeonInstance): Promise { + await leonInstance.check() + } + async execute(): Promise { try { const leonInstance = LeonInstance.get(this.name) diff --git a/src/commands/run.ts b/src/commands/run.ts new file mode 100644 index 0000000..142fbc6 --- /dev/null +++ b/src/commands/run.ts @@ -0,0 +1,56 @@ +import { Command, Option } from 'clipanion' +import execa from 'execa' + +import { LeonInstance } from '../services/LeonInstance.js' +import { log } from '../services/Log.js' +import { CheckCommand } from './check.js' +import { StartCommand } from './start.js' + +interface Builtin { + [key: string]: (leonInstance: LeonInstance) => Promise +} + +const BUILTIN_COMMANDS: Builtin = { + start: StartCommand.run, + check: CheckCommand.run +} + +const BUILTIN_COMMANDS_KEYS = Object.keys(BUILTIN_COMMANDS) + +export class RunCommand extends Command { + static paths = [['run']] + + static usage = { + description: + 'Run a npm script from a Leon Instance (e.g: `leon run train` runs `npm run train` in the leon instance folder).' + } + + public name = Option.String('--name', { + description: 'Name of the Leon instance.' + }) + + public script = Option.Proxy() + + async execute(): Promise { + try { + const script = this.script.join(' ') + const command = 'npm run ' + script + const leonInstance = LeonInstance.get(this.name) + const isBuiltin = BUILTIN_COMMANDS_KEYS.includes(script) + if (isBuiltin) { + const runCommand = BUILTIN_COMMANDS[script] + await runCommand(leonInstance) + return 0 + } + process.chdir(leonInstance.path) + await execa.command(command, { stdio: 'inherit' }) + return 0 + } catch (error) { + log.error({ + error, + commandPath: 'run' + }) + return 1 + } + } +} diff --git a/src/commands/start.ts b/src/commands/start.ts index 4ff108d..87331ea 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -20,10 +20,13 @@ export class StartCommand extends Command { description: 'Run a Leon instance with a specific name.' }) + static async run(leonInstance: LeonInstance): Promise { + await leonInstance.start() + } + async execute(): Promise { try { const leonInstance = LeonInstance.get(this.name) - leonInstance.incrementStartCount() await leonInstance.start(this.port) return 0 } catch (error) { diff --git a/src/e2e/classic.e2e.test.ts b/src/e2e/classic.e2e.test.ts index eace24a..4f26122 100644 --- a/src/e2e/classic.e2e.test.ts +++ b/src/e2e/classic.e2e.test.ts @@ -2,8 +2,10 @@ import { test1CreateBirth } from './tests/1-create-birth.js' import { test2Update } from './tests/2-update.js' import { test3Start } from './tests/3-start.js' import { test4Check } from './tests/4-check.js' +import { test5Run } from './tests/5-run.js' test1CreateBirth() test2Update() test3Start() test4Check() +test5Run() diff --git a/src/e2e/tests/1-create-birth.ts b/src/e2e/tests/1-create-birth.ts index 1507b6a..5ec6759 100644 --- a/src/e2e/tests/1-create-birth.ts +++ b/src/e2e/tests/1-create-birth.ts @@ -12,7 +12,7 @@ interface Options { export const test1CreateBirth = (options: Options = {}): void => { const { useDocker = false } = options - it('leon create birth', async () => { + test('leon create birth', async () => { const commandOptions = useDocker ? ['--docker'] : [] expect(await isExistingFile(Leon.DEFAULT_BIRTH_PATH)).toBe(false) const result = await execa( diff --git a/src/e2e/tests/2-update.ts b/src/e2e/tests/2-update.ts index 679c27e..332d102 100644 --- a/src/e2e/tests/2-update.ts +++ b/src/e2e/tests/2-update.ts @@ -3,7 +3,7 @@ import execa from 'execa' import { LeonInstance } from '../../services/LeonInstance.js' export const test2Update = (): void => { - it('leon update', async () => { + test('leon update', async () => { const leonInstance = LeonInstance.get() const oldVersion = await leonInstance.getVersion() const result = await execa('leon', ['update', '--develop']) diff --git a/src/e2e/tests/3-start.ts b/src/e2e/tests/3-start.ts index 76daefc..3bdd5a0 100644 --- a/src/e2e/tests/3-start.ts +++ b/src/e2e/tests/3-start.ts @@ -4,7 +4,7 @@ import execa from 'execa' export const test3Start = (): void => { const PORT = 1340 - it('leon start', (done) => { + test('leon start', (done) => { let startSubprocess: execa.ExecaChildProcess | null = null startSubprocess = execa('leon', ['start', `--port=${PORT}`]) waitOn({ diff --git a/src/e2e/tests/4-check.ts b/src/e2e/tests/4-check.ts index d3e53aa..3348191 100644 --- a/src/e2e/tests/4-check.ts +++ b/src/e2e/tests/4-check.ts @@ -1,7 +1,7 @@ import execa from 'execa' export const test4Check = (): void => { - it('leon check', async () => { + test('leon check', async () => { const result = await execa('leon', ['check']) expect(result.exitCode).toEqual(0) expect(result.stdout).toContain('.: CHECKING :.') diff --git a/src/e2e/tests/5-run.ts b/src/e2e/tests/5-run.ts new file mode 100644 index 0000000..82409a0 --- /dev/null +++ b/src/e2e/tests/5-run.ts @@ -0,0 +1,8 @@ +import execa from 'execa' + +export const test5Run = (): void => { + test('leon run', async () => { + const result = await execa('leon', ['run', 'train']) + expect(result.exitCode).toEqual(0) + }) +} diff --git a/src/services/LeonInstance.ts b/src/services/LeonInstance.ts index 6d33fe5..5552662 100644 --- a/src/services/LeonInstance.ts +++ b/src/services/LeonInstance.ts @@ -71,7 +71,7 @@ export class LeonInstance implements LeonInstanceOptions { } public async startClassic(LEON_PORT: string): Promise { - if (this.startCount === 0) { + if (this.startCount === 1) { const dotenvPath = path.join(this.path, '.env') if (await isExistingFile(dotenvPath)) { await fs.promises.rm(dotenvPath) @@ -94,6 +94,7 @@ export class LeonInstance implements LeonInstanceOptions { public async start(port?: number): Promise { process.chdir(this.path) const LEON_PORT = port?.toString() ?? '1337' + this.incrementStartCount() if (this.mode === 'docker') { return await this.startDocker(LEON_PORT) } @@ -195,20 +196,14 @@ export class LeonInstance implements LeonInstanceOptions { return leonInstance } - public incrementStartCount(): void { - const leonInstance = LeonInstance.find(this.name) - if (leonInstance == null) { - throw new LogError({ - message: "This instance doesn't exists, please provider another name." - }) - } - leonInstance.startCount += 1 + private incrementStartCount(): void { + this.startCount += 1 const instances = config.get('instances', []) const instance = instances.find((instance) => { return instance.name === this.name }) if (instance != null) { - instance.startCount = leonInstance.startCount + instance.startCount = this.startCount config.set('instances', instances) } }