Skip to content

Commit

Permalink
fix: setup automatic config "cleaner" for manually removed Leon insta…
Browse files Browse the repository at this point in the history
…nces
  • Loading branch information
theoludwig committed Sep 10, 2022
1 parent e1220f0 commit 6e5f5d5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 63 deletions.
64 changes: 43 additions & 21 deletions src/commands/__test__/info.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { config } from '../../services/Config.js'
import type { LeonInstanceOptions } from '../../services/LeonInstance.js'
import { LeonInstance } from '../../services/LeonInstance.js'
import { Log } from '../../services/Log.js'
import { isExistingPath } from '../../utils/isExistingPath.js'

const leonInstanceOptions: LeonInstanceOptions = {
name: 'random-name',
Expand Down Expand Up @@ -57,32 +58,56 @@ await tap.test('leon info', async (t) => {
const exitCode = await command.execute()
t.equal(exitCode, 0)
t.equal(consoleLogSpy.calledWith(chalk.cyan('\nLeon instances:\n')), true)
let infoResult = table([
[chalk.bold('Name'), leonInstance.name],
[chalk.bold('Path'), leonInstance.path],
[chalk.bold('Mode'), leonInstance.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), version]
])
infoResult += '\n------------------------------\n\n'
t.equal(consoleLogSpy.calledWith(infoResult), true)
}
)

await t.test(
'should succeeds and advise the user to create an instance',
async (t) => {
sinon.stub(console, 'log').value(() => {})
const consoleLogSpy = sinon.spy(console, 'log')
fsMock({
[config.path]: JSON.stringify({ instances: [] })
})
const command = cli.process(['info'])
const exitCode = await command.execute()
t.equal(exitCode, 0)
t.equal(
consoleLogSpy.calledWith(chalk.bold('No Leon instances found.')),
true
)
t.equal(
consoleLogSpy.calledWith(
table([
[chalk.bold('Name'), leonInstance.name],
[chalk.bold('Path'), leonInstance.path],
[chalk.bold('Mode'), leonInstance.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), version]
])
'You can give birth to a Leon instance using:'
),
true
)
t.equal(consoleLogSpy.calledWith(chalk.cyan('leon create birth')), true)
}
)

await t.test(
'should succeeds and advise the user to create an instance',
'should succeeds and advise the user to create an instance with instance path not found',
async (t) => {
sinon.stub(console, 'log').value(() => {})
const consoleLogSpy = sinon.spy(console, 'log')
fsMock({
[config.path]: JSON.stringify({ instances: [] })
[config.path]: JSON.stringify(configData)
})
const command = cli.process(['info'])
const exitCode = await command.execute()
t.equal(exitCode, 0)
t.equal(await isExistingPath(leonInstance.path), false)
t.strictSame(config.get('instances', []), [])
t.equal(
consoleLogSpy.calledWith(chalk.bold('No Leon instances found.')),
true
Expand Down Expand Up @@ -110,18 +135,15 @@ await tap.test('leon info', async (t) => {
const exitCode = await command.execute()
t.equal(exitCode, 0)
t.equal(consoleLogSpy.calledWith(chalk.cyan('\nLeon instances:\n')), true)
t.equal(
consoleLogSpy.calledWith(
table([
[chalk.bold('Name'), leonInstance.name],
[chalk.bold('Path'), `${leonInstance.path}`],
[chalk.bold('Mode'), leonInstance.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), '0.0.0']
])
),
true
)
let infoResult = table([
[chalk.bold('Name'), leonInstance.name],
[chalk.bold('Path'), leonInstance.path],
[chalk.bold('Mode'), leonInstance.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), '0.0.0']
])
infoResult += '\n------------------------------\n\n'
t.equal(consoleLogSpy.calledWith(infoResult), true)
}
)

Expand Down
70 changes: 70 additions & 0 deletions src/commands/__test__/start.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,81 @@
import tap from 'tap'
import sinon from 'sinon'
import fsMock from 'mock-fs'
import chalk from 'chalk'

import { StartCommand } from '../start.js'
import { cli } from '../../cli.js'
import type { ConfigData } from '../../services/Config.js'
import { config } from '../../services/Config.js'
import type { LeonInstanceOptions } from '../../services/LeonInstance.js'
import { LeonInstance } from '../../services/LeonInstance.js'
import { isExistingPath } from '../../utils/isExistingPath.js'

const leonInstanceOptions: LeonInstanceOptions = {
name: 'random-name',
birthDate: '2022-02-20T10:11:33.315Z',
mode: 'docker',
path: '/path',
startCount: 0
}

const leonInstance = new LeonInstance(leonInstanceOptions)
const configData: ConfigData = {
instances: [leonInstance]
}

await tap.test('leon start', async (t) => {
t.afterEach(() => {
fsMock.restore()
sinon.restore()
})

await t.test('should be instance of the command', async (t) => {
const command = cli.process(['start'])
t.equal(command instanceof StartCommand, true)
})

await t.test(
'should fails with instance not found (automatic config cleaner)',
async (t) => {
sinon.stub(console, 'error').value(() => {})
const consoleErrorSpy = sinon.spy(console, 'error')
fsMock({
[config.path]: JSON.stringify(configData)
})
const command = cli.process(['start'])
const exitCode = await command.execute()
t.equal(exitCode, 1)
t.equal(await isExistingPath(leonInstance.path), false)
t.strictSame(config.get('instances', []), [])
t.equal(
consoleErrorSpy.calledWith(
`${chalk.red('Error:')} You should have at least one instance.`
),
true
)
}
)

await t.test(
'should fails with instance not found with specified name',
async (t) => {
sinon.stub(console, 'error').value(() => {})
const consoleErrorSpy = sinon.spy(console, 'error')
fsMock({
[config.path]: JSON.stringify(configData)
})
const command = cli.process(['start', '--name="random-name"'])
const exitCode = await command.execute()
t.equal(exitCode, 1)
t.equal(
consoleErrorSpy.calledWith(
`${chalk.red(
'Error:'
)} This instance doesn't exists, please provider another name.`
),
true
)
}
)
})
28 changes: 20 additions & 8 deletions src/commands/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,36 @@ export class InfoCommand extends Command {
description: 'Name of the Leon instance.'
})

public static logNoInstancesFound(): void {
console.log(chalk.bold('No Leon instances found.'))
console.log('You can give birth to a Leon instance using:')
console.log(chalk.cyan('leon create birth'))
}

async execute(): Promise<number> {
try {
if (this.name != null) {
console.log()
const leonInstance = await LeonInstance.get(this.name)
await leonInstance.logInfo()
console.log(await leonInstance.info())
} else {
const instances = config.get('instances', [])
if (instances.length === 0) {
console.log(chalk.bold('No Leon instances found.'))
console.log('You can give birth to a Leon instance using:')
console.log(chalk.cyan('leon create birth'))
InfoCommand.logNoInstancesFound()
} else {
console.log(chalk.cyan('\nLeon instances:\n'))
let infoResult = ''
for (const instance of instances) {
const leonInstance = new LeonInstance(instance)
await leonInstance.logInfo()
console.log('------------------------------\n')
const leonInstance = await LeonInstance.find(instance.name)
if (leonInstance != null) {
infoResult += (await leonInstance.info()) + '\n'
infoResult += '------------------------------\n\n'
}
}
if (infoResult.length === 0) {
InfoCommand.logNoInstancesFound()
} else {
console.log(chalk.cyan('\nLeon instances:\n'))
console.log(infoResult)
}
}
}
Expand Down
57 changes: 32 additions & 25 deletions src/services/LeonInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface LeonInstanceOptions extends CreateOptions {

export class LeonInstance implements LeonInstanceOptions {
static readonly INVALID_VERSION = '0.0.0'
static readonly DEFAULT_START_PORT = 1337

public name: string
public path: string
Expand Down Expand Up @@ -84,7 +85,8 @@ export class LeonInstance implements LeonInstanceOptions {

public async start(port?: number): Promise<void> {
process.chdir(this.path)
const LEON_PORT = port?.toString() ?? '1337'
const LEON_PORT_STRING = port ?? LeonInstance.DEFAULT_START_PORT
const LEON_PORT = LEON_PORT_STRING.toString()
this.incrementStartCount()
if (this.mode === 'docker') {
return await this.startDocker(LEON_PORT)
Expand Down Expand Up @@ -160,24 +162,35 @@ export class LeonInstance implements LeonInstanceOptions {
return instance.name === name
})
if (instance != null) {
return new LeonInstance(instance)
const leonInstance = new LeonInstance(instance)
if (await isExistingPath(instance.path)) {
return leonInstance
}
await leonInstance.delete()
return null
}
return null
}

static async get(name?: string): Promise<LeonInstance> {
let instanceName = name ?? 'default'
const logErrorAtLeastOneInstance = new LogError({
message: 'You should have at least one instance.'
})
if (name == null) {
const instances = config.get('instances', [])
const isEmptyInstances = instances.length === 0
if (isEmptyInstances) {
throw new LogError({
message: 'You should have at least one instance.'
})
throw logErrorAtLeastOneInstance
}
return new LeonInstance(instances[0])
const firstInstance = instances[0]
instanceName = firstInstance.name
}
const leonInstance = await LeonInstance.find(name)
const leonInstance = await LeonInstance.find(instanceName)
if (leonInstance == null) {
if (name == null) {
throw logErrorAtLeastOneInstance
}
throw new LogError({
message: "This instance doesn't exists, please provider another name."
})
Expand Down Expand Up @@ -243,7 +256,7 @@ export class LeonInstance implements LeonInstanceOptions {
public async update(leon: Leon): Promise<void> {
const currentVersion = await this.getVersion()
const sourceCodePath = await leon.getSourceCode()
const sourceCodeVersion = await LeonInstance.getVersion(sourceCodePath)
const sourceCodeVersion = await this.getVersion()
if (currentVersion !== sourceCodeVersion || leon.useDevelopGitBranch) {
await fs.promises.rm(this.path, {
force: true,
Expand All @@ -254,35 +267,29 @@ export class LeonInstance implements LeonInstanceOptions {
}
}

public static async getVersion(sourceCodePath: string): Promise<string> {
const packageJsonPath = path.join(sourceCodePath, 'package.json')
public async getVersion(): Promise<string> {
const packageJsonPath = path.join(this.path, 'package.json')
let version = LeonInstance.INVALID_VERSION
if (await isExistingPath(packageJsonPath)) {
const packageJSON = await readPackage({
cwd: sourceCodePath,
cwd: this.path,
normalize: false
})
version = packageJSON.version ?? LeonInstance.INVALID_VERSION
}
return version
}

public async getVersion(): Promise<string> {
return await LeonInstance.getVersion(this.path)
}

public async logInfo(): Promise<void> {
public async info(): Promise<string> {
const birthDay = new Date(this.birthDate)
const birthDayString = date.format(birthDay, 'DD/MM/YYYY - HH:mm:ss')
const version = await this.getVersion()
console.log(
table([
[chalk.bold('Name'), this.name],
[chalk.bold('Path'), this.path],
[chalk.bold('Mode'), this.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), version]
])
)
return table([
[chalk.bold('Name'), this.name],
[chalk.bold('Path'), this.path],
[chalk.bold('Mode'), this.mode],
[chalk.bold('Birth date'), birthDayString],
[chalk.bold('Version'), version]
])
}
}
21 changes: 12 additions & 9 deletions src/services/__test__/LeonInstance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ const configData: ConfigData = {

await tap.test('services/LeonInstance', async (t) => {
await t.test('find', async (t) => {
t.beforeEach(() => {
fsMock({
[config.path]: JSON.stringify(configData)
})
})

t.afterEach(() => {
fsMock.restore()
})

await t.test('should find the instance with its name', async (t) => {
fsMock({
[config.path]: JSON.stringify(configData),
[leonInstance.path]: {}
})
const instance = await LeonInstance.find(leonInstance.name)
t.not(instance, undefined)
t.equal(instance?.name, leonInstance.name)
})

await t.test('should not find the instance with wrong name', async (t) => {
fsMock({
[config.path]: JSON.stringify(configData),
[leonInstance.path]: {}
})
const instance = await LeonInstance.find('wrong name')
t.equal(instance, null)
})
Expand All @@ -61,7 +62,8 @@ await tap.test('services/LeonInstance', async (t) => {
'should return the first instance if name is undefined',
async (t) => {
fsMock({
[config.path]: JSON.stringify(configData)
[config.path]: JSON.stringify(configData),
[leonInstance.path]: {}
})
const instance = await LeonInstance.get()
t.equal(instance.name, leonInstance.name)
Expand All @@ -84,7 +86,8 @@ await tap.test('services/LeonInstance', async (t) => {
'should return the instance with the name specified',
async (t) => {
fsMock({
[config.path]: JSON.stringify(configData)
[config.path]: JSON.stringify(configData),
[leonInstance.path]: {}
})
const instance = await LeonInstance.get(leonInstance.name)
t.equal(instance.name, leonInstance.name)
Expand Down

0 comments on commit 6e5f5d5

Please sign in to comment.