Skip to content
This repository was archived by the owner on Jan 18, 2023. It is now read-only.

Commit 3fda965

Browse files
denismukhopadovAnton Cherednikov
authored andcommitted
PTF-1276: Updated local launch
1 parent dc63abe commit 3fda965

File tree

18 files changed

+449
-20
lines changed

18 files changed

+449
-20
lines changed

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "codestore",
33
"description": "code.store CLI. Add services, deploy, debug, perform all operations from your terminal.",
4-
"version": "1.4.15",
4+
"version": "1.5.0",
55
"bin": {
66
"codestore": "./bin/run",
77
"cs": "./bin/run"
@@ -27,11 +27,13 @@
2727
"@types/inquirer": "^6.5.0",
2828
"@types/jest": "^25.2.1",
2929
"apollo-boost": "^0.4.7",
30+
"apollo-server-express": "^2.16.1",
3031
"archiver-promise": "^1.0.0",
3132
"axios": "^0.19.2",
3233
"chalk": "^3.0.0",
3334
"clear": "^0.1.0",
3435
"cli-ux": "^5.4.5",
36+
"codestore-utils": "^1.1.2",
3537
"completion": "^1.0.1",
3638
"cross-fetch": "^3.0.4",
3739
"enquirer": "^2.3.5",
@@ -44,10 +46,12 @@
4446
"open": "^7.0.3",
4547
"ora": "^4.0.3",
4648
"os": "^0.1.1",
49+
"pg": "^8.3.0",
4750
"rimraf": "^3.0.2",
4851
"tabtab": "^3.0.2",
4952
"tree-node-cli": "^1.3.0",
5053
"ts-jest": "^25.3.1",
54+
"typeorm": "^0.2.25",
5155
"unzipper": "^0.10.11",
5256
"yaml": "^1.10.0",
5357
"zip-a-folder": "0.0.12"
@@ -66,7 +70,7 @@
6670
"nyc": "^14.1.1",
6771
"ts-node": "^8.6.2",
6872
"tsconfig-paths": "^3.9.0",
69-
"typescript": "^3.8.3"
73+
"typescript": "^3.9.7"
7074
},
7175
"engines": {
7276
"node": ">=8.0.0"

src/commands/service/create.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Command from '../../lib/command';
77
import { IServiceCreate } from '../../interfaces/service.interface';
88
import { createPrefix } from '../../common/utils';
99
import FileWorker from '../../common/file-worker';
10-
import { installDependencies } from '../../lib/child-cli';
1110

1211
interface Ctx {
1312
service: {
@@ -152,12 +151,6 @@ export default class Create extends Command {
152151
this.structure = tree(uniqueName, { exclude: [/node_modules/, /dist/] });
153152
},
154153
},
155-
{
156-
title: 'Installing dependencies',
157-
task: async (ctx): Promise<void> => {
158-
await installDependencies(ctx.service.uniqueName);
159-
},
160-
},
161154
]);
162155

163156
await tasks.run();

src/commands/service/dev.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { logger } from 'codestore-utils';
2+
import { Listr, ListrTask } from 'listr2';
3+
import Command from '../../lib/command';
4+
import { bootstrap } from '../../lib/launcher';
5+
import { installDependencies } from '../../lib/child-cli';
6+
import compile from '../../lib/compiler';
7+
8+
export const flow = (context: { localConfiguration; command: Command}): ListrTask[] => [
9+
{
10+
title: 'Installing dependencies',
11+
task: async (): Promise<void> => {
12+
await installDependencies();
13+
},
14+
},
15+
{
16+
title: 'Compiling code',
17+
task: async (): Promise<void> => {
18+
await compile(await context.command.serviceWorker.loadResolversPaths(), context.command);
19+
},
20+
},
21+
];
22+
23+
export default class Dev extends Command {
24+
public static description = 'Launch your service locally';
25+
26+
public static aliases = ['dev'];
27+
28+
public async execute(): Promise<void> {
29+
const { localConfiguration } = await this.serviceWorker.loadValuesFromYaml();
30+
31+
if (!localConfiguration) {
32+
throw new Error('Cannot find localConfiguration in codestore.yaml');
33+
}
34+
35+
if (!localConfiguration || !localConfiguration.database) {
36+
throw new Error('There is no database configuration in codestore.yaml');
37+
}
38+
39+
await new Listr<{}>(flow({ localConfiguration, command: this })).run();
40+
41+
const { database, application } = localConfiguration;
42+
43+
logger.log('Starting development server');
44+
45+
await bootstrap({
46+
db: database,
47+
port: application.port,
48+
});
49+
}
50+
}

src/commands/service/generate.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { Listr, ListrTask } from 'listr2';
2-
import { yellow } from 'chalk';
32
import clear from 'clear';
43
import Command from '../../lib/command';
54
import Aliases from '../../common/constants/aliases';
65
import FileWorker from '../../common/file-worker';
76
import PromisifiedFs from '../../common/promisified-fs';
87
import Paths from '../../common/constants/paths';
9-
import { revertMigration, runMigration, compile } from '../../lib/child-cli';
10-
import Logger from '../../lib/logger';
8+
import compile from '../../lib/compiler';
119

1210
const firstLine = (str: string): string => str.split('\n')[0].replace(/:$/, '');
1311

@@ -22,7 +20,7 @@ export const generateFlow = (context: Command, error: (input: string | Error, op
2220
title: 'Compiling your code',
2321
task: async (): Promise<void> => {
2422
await PromisifiedFs.rimraf(Paths.DIST);
25-
await compile();
23+
await compile(await context.serviceWorker.loadResolversPaths(), context);
2624
},
2725
},
2826
{
@@ -33,7 +31,7 @@ export const generateFlow = (context: Command, error: (input: string | Error, op
3331
ctx.encodedZip = await FileWorker.zipFolder();
3432
},
3533
},
36-
{
34+
/* {
3735
title: 'Reverting extra migrations',
3836
task: async (ctx, task): Promise<void> => {
3937
const currentMigrations = await PromisifiedFs.readdir(Paths.MIGRATIONS);
@@ -52,10 +50,11 @@ export const generateFlow = (context: Command, error: (input: string | Error, op
5250
// eslint-disable-next-line no-param-reassign
5351
task.title = 'Extra migrations were successfully reverted';
5452
} catch (e) {
53+
console.log(e);
5554
task.skip(`Migrations were not reverted: ${firstLine(e.toString())}`);
5655
}
5756
},
58-
},
57+
}, */
5958
{
6059
title: 'Uploading service to the generator',
6160
task: async (ctx): Promise<void> => {
@@ -75,13 +74,13 @@ export const generateFlow = (context: Command, error: (input: string | Error, op
7574
await PromisifiedFs.rimraf(Paths.ENTITIES);
7675
await PromisifiedFs.rimraf(Paths.DIST);
7776
await FileWorker.saveZipFromB64(generated, Paths.DATA);
78-
await compile();
77+
await compile(await context.serviceWorker.loadResolversPaths(), context);
7978

8079
// eslint-disable-next-line no-param-reassign
8180
task.title = 'Generated code has been saved';
8281
},
8382
},
84-
{
83+
/* {
8584
title: 'Running generated migration',
8685
task: async (ctx, task): Promise<void> => {
8786
try {
@@ -93,7 +92,7 @@ export const generateFlow = (context: Command, error: (input: string | Error, op
9392
task.skip(`Migrations were not ran: ${firstLine(e.toString())}`);
9493
}
9594
},
96-
},
95+
}, */
9796
];
9897

9998
export default class Generate extends Command {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
interface IDbConfig {
2+
port: number;
3+
username: string;
4+
password: string;
5+
host: string;
6+
database: string;
7+
}
8+
9+
interface IApplicationConfig {
10+
port: number;
11+
}
12+
113
export default interface IServiceConfig {
214
serviceId: number;
15+
localConfiguration: {
16+
database: IDbConfig;
17+
application: IApplicationConfig;
18+
};
319
}

src/lib/api-client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export default class APIClient {
3636
}
3737

3838
public async loginWeb(): Promise<any> {
39+
await this.homeFolderService.removeToken();
40+
3941
// opening browser. See openBrowser.ts for change configurations
4042
await openBrowser();
4143
return new Promise((resolve, reject) => {

src/lib/child-cli/child-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const runMigration = (): Promise<void> => runCommand('npm run migration:run');
1818

1919
const revertMigration = (): Promise<void> => runCommand('npm run migration:revert');
2020

21-
const installDependencies = (serviceName: string): Promise<void> => runCommand(`cd ${serviceName} && npm install`);
21+
const installDependencies = (serviceName?: string): Promise<void> => (serviceName ? runCommand(`cd ${serviceName} && npm install`) : runCommand('npm install'));
2222

2323
export {
2424
compile,

src/lib/compiler.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { join } from 'path';
2+
import * as ts from 'typescript';
3+
import Command from './command';
4+
import PromisifiedFs from '../common/promisified-fs';
5+
6+
export default async (files: any, command: Command): Promise<void> => {
7+
const program = ts.createProgram(files, {
8+
declaration: true,
9+
importHelpers: true,
10+
module: 1, // commonjs
11+
target: 4, // es2017
12+
esModuleInterop: true,
13+
strictNullChecks: true,
14+
emitDecoratorMetadata: true,
15+
experimentalDecorators: true,
16+
strict: false,
17+
outDir: 'temp',
18+
});
19+
const emitResult = program.emit();
20+
21+
const allDiagnostics = ts
22+
.getPreEmitDiagnostics(program)
23+
.concat(emitResult.diagnostics);
24+
25+
allDiagnostics.forEach((diagnostic) => {
26+
if (diagnostic.file) {
27+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
28+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
29+
command.error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
30+
} else {
31+
command.log(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
32+
}
33+
});
34+
35+
await PromisifiedFs.rimraf(join(process.cwd(), 'temp'));
36+
};

src/lib/launcher/Application.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ApolloServer } from 'apollo-server-express';
2+
import GraphqlLoader from './GraphQLLoader';
3+
import DatabaseLoader from './DatabaseLoader';
4+
import { IConfig } from './interfaces/config.interface';
5+
6+
export default class Application {
7+
private gqlLoader: GraphqlLoader = new GraphqlLoader();
8+
9+
private dbLoader: DatabaseLoader;
10+
11+
public constructor(public readonly config: IConfig) {
12+
this.dbLoader = new DatabaseLoader(config);
13+
}
14+
15+
public async buildServer(): Promise<ApolloServer> {
16+
try {
17+
const { connection, repositories }: any = await this.dbLoader.getDbConnector();
18+
19+
return new ApolloServer({
20+
playground: true,
21+
introspection: true,
22+
typeDefs: await this.gqlLoader.getTypeDefs(),
23+
resolvers: await this.gqlLoader.getResolvers(),
24+
uploads: false,
25+
context: (): object => ({
26+
db: {
27+
connection,
28+
repositories,
29+
},
30+
}),
31+
});
32+
} catch (e) {
33+
throw new Error(`Server failed to start, error: ${e}`);
34+
}
35+
}
36+
}

src/lib/launcher/DatabaseLoader.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import fs from 'fs';
2+
import { createConnection, Connection } from 'typeorm';
3+
import path from 'path';
4+
import { logger } from 'codestore-utils';
5+
import { IRepositories, IConnector } from './interfaces/database.interface';
6+
import { IConfig } from './interfaces/config.interface';
7+
8+
export default class DatabaseConnector {
9+
private entitiesPath = path.join(process.cwd(), 'src', 'data', 'entities', '*.ts');
10+
11+
private migrationsPath = path.join(process.cwd(), 'src', 'data', 'migrations', '*.ts');
12+
13+
public constructor(private readonly config: IConfig) {
14+
}
15+
16+
public async getDbConnector(): Promise<IConnector> {
17+
const connection = await this.createConnection();
18+
const repositories = await this.loadModels(connection);
19+
20+
const context = this.constructor.name;
21+
logger.log(`Loaded entities: ${Object.keys(repositories)}`, context);
22+
23+
return {
24+
connection,
25+
repositories,
26+
};
27+
}
28+
29+
private async createConnection(): Promise<Connection> {
30+
const context = this.constructor.name;
31+
32+
logger.log('Connecting to database', context);
33+
34+
const connection = await createConnection({
35+
type: 'postgres',
36+
...this.config.db,
37+
entities: [
38+
path.normalize(this.entitiesPath),
39+
],
40+
migrations: [this.migrationsPath],
41+
name: 'default',
42+
});
43+
44+
logger.log(`Successfully connected to database ${this.config.db.database}`, context);
45+
46+
logger.log('Running migrations', context);
47+
try {
48+
await connection.runMigrations();
49+
} catch (e) {
50+
await connection.undoLastMigration();
51+
await connection.runMigrations();
52+
}
53+
54+
return connection;
55+
}
56+
57+
private async loadModels(connection: Connection): Promise<IRepositories> {
58+
let modelFiles;
59+
try {
60+
modelFiles = fs.readdirSync(path.join(process.cwd(), 'src', 'data', 'entities'))
61+
.filter((file) => /.ts$/.test(file))
62+
.map(async (modelFile) => import(`${path.join(process.cwd(), 'src', 'data', 'entities')}/${modelFile}`));
63+
} catch (e) {
64+
if (e?.code !== 'ENOENT') {
65+
logger.error(e, undefined, this.constructor.name);
66+
}
67+
return {};
68+
}
69+
70+
const loadedEntities = await Promise.all(modelFiles) as any[];
71+
72+
return loadedEntities.reduce((prev, next) => {
73+
const value: any = Object.values(next)[0];
74+
const { name } = value;
75+
76+
return {
77+
...prev,
78+
[name]: connection.getRepository(value),
79+
};
80+
}, {});
81+
}
82+
}

0 commit comments

Comments
 (0)