Skip to content
Merged
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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "monux-cli",
"version": "2.2.3",
"version": "2.2.4",
"license": "MIT",
"main": "index.js",
"engines": {
Expand Down
51 changes: 30 additions & 21 deletions src/commands/add/add-loopback/add-loopback.command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { loopbackViteContent } from './loopback-vite.content';
import { loopbackWebpackContent } from './loopback-webpack.content';
import { APPS_DIRECTORY_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, DOCKER_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, GIT_IGNORE_FILE_NAME, TS_CONFIG_FILE_NAME, WEBPACK_CONFIG, BASE_TS_CONFIG_FILE_NAME } from '../../../constants';
import { APPS_DIRECTORY_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, DOCKER_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, GIT_IGNORE_FILE_NAME, TS_CONFIG_FILE_NAME, WEBPACK_CONFIG, BASE_TS_CONFIG_FILE_NAME, VITE_CONFIG } from '../../../constants';
import { DbType, DbUtilities } from '../../../db';
import { DockerUtilities } from '../../../docker';
import { FsUtilities, QuestionsFor } from '../../../encapsulation';
Expand Down Expand Up @@ -93,7 +94,7 @@ export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration>

await Promise.all([
this.setupTsConfig(config.name),
this.updateApplicationTs(root),
this.updateApplicationTs(root, databaseName),
this.updateIndexTs(root, config.port),
this.updateOpenApiSpec(root, config.port),
EslintUtilities.setupProjectEslint(root, true, TS_CONFIG_FILE_NAME),
Expand All @@ -112,14 +113,14 @@ export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration>
config.subDomain
),
this.updateDockerFile(root, config)
// this.setupVite(root, config.name)
// this.setupWebpack(root, config.name) TODO: enable
]);

await NpmUtilities.updatePackageJson(config.name, {
scripts: {
start: 'npm run start:watch',
'start:watch': 'tsc-watch --target es2017 --outDir ./dist --onSuccess \"node .\"'
// 'build:webpack': 'webpack' TODO: enable
}
});
await NpmUtilities.install(config.name, [NpmPackage.TSC_WATCH], true);
Expand All @@ -132,24 +133,24 @@ export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration>
await EnvUtilities.buildEnvironmentFileForApp(app, false, 'dev.docker-compose.yaml', getPath('.'));
}

private async setupVite(root: Path, projectName: string): Promise<void> {
await FsUtilities.createFile(getPath(root, VITE_CONFIG), loopbackViteContent);
await NpmUtilities.install(projectName, [NpmPackage.VITE, NpmPackage.VITE_TS_CONFIG_PATHS], true);
await NpmUtilities.updatePackageJson(projectName, {
scripts: {
'build:vite': 'vite build'
}
});
}

private async setupWebpack(root: Path, projectName: string): Promise<void> {
await FsUtilities.createFile(getPath(root, WEBPACK_CONFIG), loopbackWebpackContent);
await NpmUtilities.install(
projectName,
[
NpmPackage.WEBPACK,
NpmPackage.WEBPACK_CLI,
NpmPackage.TS_LOADER,
NpmPackage.WEBPACK_NODE_EXTERNALS,
NpmPackage.TSCONFIG_PATH_WEBPACK_PLUGIN,
NpmPackage.FORK_TS_CHECKER_WEBPACK_PLUGIN
],
true
);
await NpmUtilities.install(projectName, [
NpmPackage.CLDRJS,
NpmPackage.CLDR_DATA
]);
await NpmUtilities.install(projectName, [NpmPackage.WEBPACK, NpmPackage.WEBPACK_CLI], true);
await NpmUtilities.updatePackageJson(projectName, {
scripts: {
'build:webpack': 'webpack'
}
});
}

private async updateDockerFile(root: string, config: AddLoopbackConfiguration): Promise<void> {
Expand Down Expand Up @@ -181,7 +182,10 @@ export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration>
await FsUtilities.replaceInFile(
indexPath,
' await app.boot();',
' await app.boot();\n await app.migrateSchema({ existingSchema: \'alter\' });'
[
' await app.boot();',
' await app.migrateSchema({ existingSchema: \'alter\' });'
].join('\n')
);
await FsUtilities.replaceInFile(indexPath, 'env.PORT', 'env[\'PORT\']');
await FsUtilities.replaceInFile(indexPath, 'env.HOST', 'env[\'HOST\']');
Expand All @@ -196,13 +200,18 @@ export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration>
await FsUtilities.replaceInFile(openApiPath, '?? 3000', `?? ${port}`);
}

private async updateApplicationTs(root: string): Promise<void> {
private async updateApplicationTs(root: string, dbName: string): Promise<void> {
const applicationPath: Path = getPath(root, 'src', 'application.ts');
await FsUtilities.replaceInFile(
applicationPath,
'BootMixin(RestApplication)',
'BootMixin(ServiceMixin(RepositoryMixin(RestApplication)))'
);
await TsUtilities.addToConstructorBody(
applicationPath,
// eslint-disable-next-line stylistic/max-len
`this.dataSource(${toPascalCase(dbName)}DataSource, 'db'); // "db" is the key under wich the datasource is registered in teh external components`
);
await TsUtilities.addImportStatements(
applicationPath,
[
Expand Down
22 changes: 22 additions & 0 deletions src/commands/add/add-loopback/loopback-vite.content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

// eslint-disable-next-line jsdoc/require-jsdoc
export const loopbackViteContent: string = `import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
plugins: [tsconfigPaths()],
build: {
ssr: 'src/index.ts',
target: 'node20',
outDir: 'dist',
emptyOutDir: true,
rollupOptions: {
output: {
format: 'cjs',
entryFileNames: '[name].js',
chunkFileNames: '[name].js',
inlineDynamicImports: true
}
}
}
});`;
1 change: 0 additions & 1 deletion src/commands/init/init.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export class InitCommand extends BaseCommand<InitConfiguration> {
ENV_FILE_NAME,
ENVIRONMENT_TS_FILE_NAME,
ROBOTS_FILE_NAME,
'**/init/**.sh',
'**/init/**.sql',
'letsencrypt',
'# compiled output',
Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ export const NEST_CLI_FILE_NAME: string = 'nest-cli.json';
*/
export const WEBPACK_CONFIG: string = 'webpack.config.js';

/**
* The name of the vite config file.
*/
export const VITE_CONFIG: string = 'vite.config.ts';

/**
* The message to notify the user of the help command.
*/
Expand Down
28 changes: 20 additions & 8 deletions src/db/db-utilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,30 @@ describe('DbUtilities', () => {

await DbUtilities.createInitFiles('dev.docker-compose.yaml', getPath('.'));

const initShContent: string[] = await FsUtilities.readFileLines(getPath(mockConstants.PROJECT_DIR, DATABASES_DIRECTORY_NAME, 'postgres-db', 'init', '0.sh'));
const postgresInitContent: string[] = await FsUtilities.readFileLines(getPath(mockConstants.PROJECT_DIR, DATABASES_DIRECTORY_NAME, 'postgres-db', 'init', '0.sql'));
const postgresPassword: string = await EnvUtilities.getEnvVariable(DefaultEnvKeys.dbPassword(POSTGRES_SERVICE_NAME, POSTGRES_DATABASE_NAME), 'dev.docker-compose.yaml', getPath('.'));
const initSqlContent: string[] = await FsUtilities.readFileLines(getPath(mockConstants.PROJECT_DIR, DATABASES_DIRECTORY_NAME, 'maria-db', 'init', '0.sql'));
const mariadbInitContent: string[] = await FsUtilities.readFileLines(getPath(mockConstants.PROJECT_DIR, DATABASES_DIRECTORY_NAME, 'maria-db', 'init', '0.sql'));
const mariadbPassword: string = await EnvUtilities.getEnvVariable(DefaultEnvKeys.dbPassword(MARIADB_SERVICE_NAME, MARIADB_DATABASE_NAME), 'dev.docker-compose.yaml', getPath('.'));

expect(initShContent).toEqual([
'#!/bin/bash',
'psql -tc "SELECT 1 FROM pg_database WHERE datname = \'test2\'" | grep -q 1 || psql -c "CREATE DATABASE test2"',
`psql -tc "SELECT 1 FROM pg_roles WHERE rolname = 'test2_user'" | grep -q 1 || psql -c "CREATE USER test2_user WITH PASSWORD '${postgresPassword}'"`,
'psql -c "GRANT ALL PRIVILEGES ON DATABASE test2 TO test2_user"'
expect(postgresInitContent).toEqual([
'-- 1) Create DB if missing',
'SELECT format(\'CREATE DATABASE %I\', \'test2\')',
' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = \'test2\')\\gexec',
'',
'-- 2) Create user if missing',
'SELECT format(',
' \'CREATE USER %I WITH PASSWORD %L\',',
' \'test2_user\',',
` '${postgresPassword}'`,
')',
' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = \'test2_user\')\\gexec',
'',
'-- 3) Grant privileges',
'GRANT ALL PRIVILEGES ON DATABASE "test2" TO "test2_user";',
'\\connect test2',
'GRANT ALL PRIVILEGES ON SCHEMA public TO test2_user;'
]);
expect(initSqlContent).toEqual([
expect(mariadbInitContent).toEqual([
'CREATE DATABASE IF NOT EXISTS `test`;',
'',
`CREATE USER IF NOT EXISTS 'test_user'@'%' IDENTIFIED BY '${mariadbPassword}';`,
Expand Down
29 changes: 18 additions & 11 deletions src/db/db.utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,15 @@ export abstract class DbUtilities {
for (const db of dbs) {
const configs: DbInitConfig[] = await this.getInitConfigsForDb(db.name, rootDir);
for (let i: number = 0; i < configs.length; i++) {
const initFileSh: Path = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sh`);
const initFileSql: Path = getPath(rootDir, DATABASES_DIRECTORY_NAME, toKebabCase(db.name), 'init', `${i}.sql`);
await FsUtilities.rm(initFileSh);
await FsUtilities.rm(initFileSql);
await this.createInitFile(configs[i], initFileSh, initFileSql, fileName, rootDir);
await this.createInitFile(configs[i], initFileSql, fileName, rootDir);
}
}
}

private static async createInitFile(
config: DbInitConfig,
initFileSh: Path,
initFileSql: Path,
fileName: DockerComposeFileName,
rootDir: string
Expand All @@ -93,14 +90,24 @@ export abstract class DbUtilities {
switch (config.type) {
case DbType.POSTGRES: {
await FsUtilities.createFile(
initFileSh,
initFileSql,
[
'#!/bin/bash',
// eslint-disable-next-line stylistic/max-len
`psql -tc "SELECT 1 FROM pg_database WHERE datname = '${dbName}'" | grep -q 1 || psql -c "CREATE DATABASE ${dbName}"`,
// eslint-disable-next-line stylistic/max-len
`psql -tc "SELECT 1 FROM pg_roles WHERE rolname = '${dbUser}'" | grep -q 1 || psql -c "CREATE USER ${dbUser} WITH PASSWORD '${dbPassword}'"`,
`psql -c "GRANT ALL PRIVILEGES ON DATABASE ${dbName} TO ${dbUser}"`
'-- 1) Create DB if missing',
`SELECT format('CREATE DATABASE %I', '${dbName}')`,
` WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${dbName}')\\gexec`,
'',
'-- 2) Create user if missing',
'SELECT format(',
' \'CREATE USER %I WITH PASSWORD %L\',',
` '${dbUser}',`,
` '${dbPassword}'`,
')',
` WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${dbUser}')\\gexec`,
'',
'-- 3) Grant privileges',
`GRANT ALL PRIVILEGES ON DATABASE "${dbName}" TO "${dbUser}";`,
`\\connect ${dbName}`,
`GRANT ALL PRIVILEGES ON SCHEMA public TO ${dbUser};`
]
);
break;
Expand Down
5 changes: 4 additions & 1 deletion src/npm/npm-package.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@ export enum NpmPackage {
TYPEORM = 'typeorm',
PG = 'pg',
MYSQL_2 = 'mysql2',
// TODO: clean up after loopback4 bundling
WEBPACK = 'webpack',
WEBPACK_CLI = 'webpack-cli',
TS_LOADER = 'ts-loader',
WEBPACK_NODE_EXTERNALS = 'webpack-node-externals',
TSCONFIG_PATH_WEBPACK_PLUGIN = 'tsconfig-paths-webpack-plugin',
FORK_TS_CHECKER_WEBPACK_PLUGIN = 'fork-ts-checker-webpack-plugin',
CLDRJS = 'cldrjs',
CLDR_DATA = 'cldr-data'
CLDR_DATA = 'cldr-data',
VITE = 'vite',
VITE_TS_CONFIG_PATHS = 'vite-tsconfig-paths'
}