Skip to content

Commit ddf6ac5

Browse files
committed
added global docker services handling, refactored commands to class based, removed up/down variants
1 parent b35a418 commit ddf6ac5

67 files changed

Lines changed: 1125 additions & 908 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The projects that can be added to a Monux monorepo also provide a lot of functio
4141
- [Adding a new project to the monorepo](#adding-a-new-project-to-the-monorepo)
4242
- [Running development services](#running-development-services)
4343
- [Listing monorepo services](#listing-monorepo-services)
44+
- [Stopping development services](#stopping-development-services)
4445
- [Running npm scripts](#running-npm-scripts)
4546
- [Running npm scripts in multiple projects](#running-npm-scripts-in-multiple-projects)
4647
- [Handling environment variables](#handling-environment-variables)
@@ -55,6 +56,7 @@ The projects that can be added to a Monux monorepo also provide a lot of functio
5556
- [How do they work?](#how-do-they-work)
5657
- [Starting prod locally](#starting-prod-locally)
5758
- [Starting in production](#starting-in-production)
59+
- [Global Management of Monorepos](#global-management-of-monorepos)
5860
- [Supported project types](#supported-project-types)
5961
- [Angular app](#angular-app)
6062
- [Angular website](#angular-website)
@@ -107,13 +109,22 @@ That section also includes a guide on how to add projects manually.
107109

108110
## Running development services
109111
Some things like databases will be added to the monorepo solely in the docker compose.<br>
110-
To use these during development, the cli includes the `mx up-dev` command.
112+
To use these during development, the cli includes the `mx up` command, where you can provide the "dev" environment when prompted.
111113

112114
## Listing monorepo services
113115
To list all of Monux monorepos and their respective docker services we included the `mx ls` and `mx la` commands.
114116

115117
Where `ls` or `list` only shows monorepos with currently running docker services, while `la` or `list-all` also shows monorepos with stopped docker services.
116118

119+
Both of these commands finds Monux workspaces globally. The only constraint for being found is that `mx up` had to be used at least once.
120+
121+
## Stopping development services
122+
To stop your services again, Monux provides the `mx down` command.
123+
124+
>If you are used to docker:<br>
125+
>Please note that this is NOT equivalent to `docker compose down`.
126+
>This actually uses `docker compose stop` internally.
127+
117128
## Running npm scripts
118129
To run an npm script of one of your projects you can use `mx {projectName} {npmScript}`. This works for projects in the "apps" and "libs" directories of your monorepo.
119130

@@ -135,7 +146,7 @@ How these environment files are generated depends on a `environment.model.ts`-fi
135146
That way it is possible to only have certain variables like an contact email-address be available to a website project, while certain other variables like a db-password are not.
136147

137148
### Calculated environment variables
138-
Working with static variables can sometimes be pretty tedious. This is especially true when you want to support different "modes" in which to launch your application (like we do with the `mx up`, `mx up-dev` or `mx up-local` commands).<br>
149+
Working with static variables can sometimes be pretty tedious. This is especially true when you want to support different "modes" in which to launch your application (like we do with the different options for `mx up`).<br>
139150
For example, if we defined the variables "api_base_url", "website_base_url" and "admin_base_url" all statically, we would need to manually fiddle with the `.env`-file anytime we switch between dev and local.<br>
140151
To solve this, Monux implements calculated environment variables.
141152

@@ -240,7 +251,7 @@ Notice that these files also include a Environment type for the specific project
240251

241252
#### Automatically create the projects environment.ts files
242253
The `environment.ts` that is used by the project needs to be generated by running `mx prepare`. This will also take care of the validation mentioned before.<br>
243-
When you use any of `mx up`, `mx up-dev` or `mx up-local` to deploy the project, the `mx prepare` command is actually called internally, so you don't have to call it manually.
254+
When you use `mx up` to deploy the project, the `mx prepare` command is actually called internally, so you don't have to call it manually.
244255

245256
## Handling initial database content
246257
Because Docker Compose environment variables can often only initialize 1 default user and 1 default db, Monux provides a way to add multiple of these during the `mx prepare` command.
@@ -268,15 +279,23 @@ Monux handles everything regarding mapping these variable names back to values a
268279
## Starting prod locally
269280
Often times you want to test your project under production like constraints (eg. when developing a website to check its SEO performance).
270281

271-
For that Monux provides the command `mx up-local`.
282+
For that, you can run `mx up` with the environment "local".
272283

273284
## Starting in production
274-
You can start the whole monorepo with the single command `mx up`.
285+
You can start the whole monorepo with running `mx up` and then selecting "prod" as the environment.
275286

276287
This will try to run the `mx prepare` command.<br>
277288
The only info required by that command is inside the `.env`-file.<br>
278289
Monux also validates the `.env`-file, so by continueously running the command you can fill it little by little and don't need to worry that you start your monorepo with invalid or missing environment variables.
279290

291+
## Global Management of Monorepos
292+
The Monux cli commands `mx up`, `mx down`, `mx ls` and `mx la` can be run globally. That way you don't have to open up a certain directory just to exit some services.
293+
294+
The way this works is by supplying an additional argument to `up` and `down`: The name of the monorepo.
295+
296+
The name of the monorepo is simply the directory name. If you are unsure about that or don't quite now what is currently running, you can simply use the `mx ls`/`mx la` commands.<br>
297+
They will give you a nice overview of all monorepos on your machine and their respective services, including if they are running or not.
298+
280299
# Supported project types
281300
## Angular app
282301
## Angular website

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "monux-cli",
3-
"version": "2.1.2",
3+
"version": "2.2.0",
44
"license": "MIT",
55
"main": "index.js",
66
"engines": {

src/angular/angular.utilities.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,15 @@ export abstract class AngularUtilities {
177177
name,
178178
getPath(projectRoot, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME),
179179
DefaultEnvKeys.baseUrl(apiName),
180-
false
180+
false,
181+
getPath('.')
181182
);
182183
await EnvUtilities.addProjectVariableKey(
183184
name,
184185
getPath(projectRoot, 'src', 'environment', ENVIRONMENT_MODEL_TS_FILE_NAME),
185186
DefaultEnvKeys.domain(apiName),
186-
false
187+
false,
188+
getPath('.')
187189
);
188190
const authServicePath: string = getPath(projectRoot, 'src', 'app', 'services', 'auth.service.ts');
189191
await FsUtilities.createFile(authServicePath, authServiceContent);
@@ -619,8 +621,8 @@ export abstract class AngularUtilities {
619621
* @param domain - The domain of the project. Is needed to create the robots.txt file when the baseUrl environment variable has not been set yet.
620622
*/
621623
static async addSitemapAndRobots(root: string, projectName: string, domain: string): Promise<void> {
622-
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(projectName);
623-
await RobotsUtilities.createRobotsTxtForApp(app, 'dev.docker-compose.yaml', domain);
624+
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(projectName, getPath('.'));
625+
await RobotsUtilities.createRobotsTxtForApp(app, 'dev.docker-compose.yaml', domain, getPath('.'));
624626
await FsUtilities.createFile(getPath(root, 'src', SITEMAP_FILE_NAME), [
625627
'<?xml version="1.0" encoding="UTF-8"?>',
626628
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">',

src/commands/add/add-angular-library/add-angular-library.command.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { TsConfig, TsConfigUtilities } from '../../../tsconfig';
99
import { OmitStrict } from '../../../types';
1010
import { getPath, mergeDeep } from '../../../utilities';
1111
import { WorkspaceConfig, WorkspaceProject, WorkspaceUtilities } from '../../../workspace';
12-
import { AddCommand } from '../models';
12+
import { BaseAddCommand } from '../models';
1313
import { AddConfiguration } from '../models/add-configuration.model';
1414

1515
/**
@@ -33,7 +33,7 @@ type CreateResult = {
3333
/**
3434
* Command that handles adding an angular library to the monorepo.
3535
*/
36-
export class AddAngularLibraryCommand extends AddCommand<AddAngularLibraryConfiguration> {
36+
export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryConfiguration> {
3737

3838
protected override configQuestions: QuestionsFor<OmitStrict<AddAngularLibraryConfiguration, keyof AddConfiguration>> = {
3939
scope: {
@@ -118,7 +118,7 @@ export class AddAngularLibraryCommand extends AddCommand<AddAngularLibraryConfig
118118
[PACKAGE_JSON_FILE_NAME]
119119
);
120120

121-
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
121+
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
122122
return { root: newProject.path, oldPackageJson };
123123
}
124124

src/commands/add/add-angular-website/add-angular-website.command.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { TsConfig, TsConfigUtilities } from '../../../tsconfig';
1010
import { OmitStrict } from '../../../types';
1111
import { getPath, toPascalCase } from '../../../utilities';
1212
import { WorkspaceProject, WorkspaceUtilities } from '../../../workspace';
13-
import { AddCommand } from '../models';
13+
import { BaseAddCommand } from '../models';
1414
import { AddConfiguration } from '../models/add-configuration.model';
1515

1616
/**
@@ -41,7 +41,7 @@ type AddAngularWebsiteConfiguration = AddConfiguration & {
4141
/**
4242
* Command that handles adding an angular website to the monorepo.
4343
*/
44-
export class AddAngularWebsiteCommand extends AddCommand<AddAngularWebsiteConfiguration> {
44+
export class AddAngularWebsiteCommand extends BaseAddCommand<AddAngularWebsiteConfiguration> {
4545

4646
protected override configQuestions: QuestionsFor<OmitStrict<AddAngularWebsiteConfiguration, keyof AddConfiguration>> = {
4747
port: {
@@ -75,7 +75,8 @@ export class AddAngularWebsiteCommand extends AddCommand<AddAngularWebsiteConfig
7575

7676
const prodRootDomain: string = await EnvUtilities.getEnvVariable(
7777
DefaultEnvKeys.PROD_ROOT_DOMAIN,
78-
'dev.docker-compose.yaml'
78+
'dev.docker-compose.yaml',
79+
getPath('.')
7980
);
8081
const domain: string = config.subDomain ? `${config.subDomain}.${prodRootDomain}` : prodRootDomain;
8182

@@ -111,8 +112,8 @@ export class AddAngularWebsiteCommand extends AddCommand<AddAngularWebsiteConfig
111112
await AngularUtilities.setupTracking(config.name);
112113
}
113114
await NpmUtilities.updatePackageJson(config.name, { scripts: { start: `ng serve --port ${config.port}` } });
114-
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
115-
await EnvUtilities.buildEnvironmentFileForApp(app, true, 'dev.docker-compose.yaml');
115+
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
116+
await EnvUtilities.buildEnvironmentFileForApp(app, true, 'dev.docker-compose.yaml', getPath('.'));
116117
}
117118

118119
private async createDefaultPages(root: string, titleSuffix: string, domain: string): Promise<void> {
@@ -236,7 +237,7 @@ export class AddAngularWebsiteCommand extends AddCommand<AddAngularWebsiteConfig
236237
`new ${config.name}`,
237238
{ '--skip-git': true, '--style': 'css', '--inline-style': true, '--ssr': true }
238239
);
239-
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
240+
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
240241
await FsUtilities.updateFile(getPath(newProject.path, 'src', 'app', 'app.component.html'), '', 'replace');
241242
await AngularUtilities.addProvider(newProject.path, 'provideHttpClient(withInterceptorsFromDi(), withFetch())', [
242243
// eslint-disable-next-line sonar/no-duplicate-string

src/commands/add/add-angular/add-angular.command.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import { TsConfig, TsConfigUtilities } from '../../../tsconfig';
1111
import { OmitStrict } from '../../../types';
1212
import { getPath, toPascalCase } from '../../../utilities';
1313
import { WorkspaceProject, WorkspaceUtilities } from '../../../workspace';
14-
import { AddCommand } from '../models/add-command.class';
15-
import { AddConfiguration } from '../models/add-configuration.model';
14+
import { BaseAddCommand, AddConfiguration } from '../models';
1615

1716
/**
1817
* Configuration for adding a new angular app.
@@ -42,7 +41,7 @@ type AddAngularConfiguration = AddConfiguration & {
4241
/**
4342
* Command that handles adding an angular application to the monorepo.
4443
*/
45-
export class AddAngularCommand extends AddCommand<AddAngularConfiguration> {
44+
export class AddAngularCommand extends BaseAddCommand<AddAngularConfiguration> {
4645
protected override readonly configQuestions: QuestionsFor<OmitStrict<AddAngularConfiguration, keyof AddConfiguration>> = {
4746
port: {
4847
type: 'number',
@@ -100,7 +99,11 @@ export class AddAngularCommand extends AddCommand<AddAngularConfiguration> {
10099
AngularUtilities.setupMaterial(root)
101100
]);
102101

103-
const prodRootDomain: string = await EnvUtilities.getEnvVariable(DefaultEnvKeys.PROD_ROOT_DOMAIN, 'dev.docker-compose.yaml');
102+
const prodRootDomain: string = await EnvUtilities.getEnvVariable(
103+
DefaultEnvKeys.PROD_ROOT_DOMAIN,
104+
'dev.docker-compose.yaml',
105+
getPath('.')
106+
);
104107
const fullDomain: string = config.subDomain ? `${config.subDomain}.${prodRootDomain}` : prodRootDomain;
105108

106109
await AngularUtilities.setupNavigation(root, config.name);
@@ -119,8 +122,8 @@ export class AddAngularCommand extends AddCommand<AddAngularConfiguration> {
119122

120123
await NpmUtilities.updatePackageJson(config.name, { scripts: { start: `ng serve --port ${config.port}` } });
121124

122-
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
123-
await EnvUtilities.buildEnvironmentFileForApp(app, false, 'dev.docker-compose.yaml');
125+
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
126+
await EnvUtilities.buildEnvironmentFileForApp(app, false, 'dev.docker-compose.yaml', getPath('.'));
124127
}
125128

126129
private async setupTailwind(root: string): Promise<void> {
@@ -189,7 +192,7 @@ export class AddAngularCommand extends AddCommand<AddAngularConfiguration> {
189192
`new ${config.name}`,
190193
{ '--skip-git': true, '--style': 'css', '--inline-style': true, '--ssr': true }
191194
);
192-
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
195+
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
193196
await FsUtilities.updateFile(getPath(newProject.path, 'src', 'app', 'app.component.html'), '', 'replace');
194197
await AngularUtilities.addProvider(newProject.path, 'provideHttpClient(withInterceptorsFromDi(), withFetch())', [
195198
// eslint-disable-next-line sonar/no-duplicate-string

src/commands/add/add-loopback/add-loopback.command.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { TsConfigUtilities } from '../../../tsconfig';
1111
import { OmitStrict } from '../../../types';
1212
import { getPath, toKebabCase, toPascalCase } from '../../../utilities';
1313
import { WorkspaceProject, WorkspaceUtilities } from '../../../workspace';
14-
import { AddCommand } from '../models';
14+
import { BaseAddCommand } from '../models';
1515
import { AddConfiguration } from '../models/add-configuration.model';
1616

1717
/**
@@ -46,7 +46,7 @@ export type AddLoopbackConfiguration = AddConfiguration & {
4646
/**
4747
* Command that handles adding a loopback api to the monorepo.
4848
*/
49-
export class AddLoopbackCommand extends AddCommand<AddLoopbackConfiguration> {
49+
export class AddLoopbackCommand extends BaseAddCommand<AddLoopbackConfiguration> {
5050
protected override configQuestions: QuestionsFor<OmitStrict<AddLoopbackConfiguration, keyof AddConfiguration>> = {
5151
port: {
5252
type: 'number',
@@ -80,7 +80,7 @@ export class AddLoopbackCommand extends AddCommand<AddLoopbackConfiguration> {
8080

8181
override async run(): Promise<void> {
8282
const config: AddLoopbackConfiguration = await this.getConfig();
83-
const { dbServiceName, databaseName } = await DbUtilities.configureDb(config.name);
83+
const { dbServiceName, databaseName } = await DbUtilities.configureDb(config.name, undefined, getPath('.'));
8484
const root: string = await this.createProject(config);
8585
await EnvUtilities.setupProjectEnvironment(root, false);
8686
await this.createLoopbackDatasource(dbServiceName, databaseName, root, config.name);
@@ -119,8 +119,8 @@ export class AddLoopbackCommand extends AddCommand<AddLoopbackConfiguration> {
119119
await LoopbackUtilities.setupChangeSets(root, config.name);
120120
await LoopbackUtilities.setupMigrations(root, config.name);
121121

122-
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
123-
await EnvUtilities.buildEnvironmentFileForApp(app, false, 'dev.docker-compose.yaml');
122+
const app: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
123+
await EnvUtilities.buildEnvironmentFileForApp(app, false, 'dev.docker-compose.yaml', getPath('.'));
124124
}
125125

126126
private async updateDockerFile(root: string): Promise<void> {
@@ -221,11 +221,22 @@ export class AddLoopbackCommand extends AddCommand<AddLoopbackConfiguration> {
221221
projectName,
222222
environmentModel,
223223
DefaultEnvKeys.dbPassword(dbServiceName, databaseName),
224-
true
224+
true,
225+
getPath('.')
225226
);
226-
await EnvUtilities.addProjectVariableKey(projectName, environmentModel, DefaultEnvKeys.dbUser(dbServiceName, databaseName), true);
227-
await EnvUtilities.addProjectVariableKey(projectName, environmentModel, DefaultEnvKeys.dbName(dbServiceName, databaseName), true);
228-
await EnvUtilities.addProjectVariableKey(projectName, environmentModel, DefaultEnvKeys.dbHost(dbServiceName), true);
227+
await EnvUtilities.addProjectVariableKey(
228+
projectName,
229+
environmentModel,
230+
DefaultEnvKeys.dbUser(dbServiceName, databaseName),
231+
true,
232+
getPath('.')
233+
);
234+
await EnvUtilities.addProjectVariableKey(projectName,
235+
environmentModel,
236+
DefaultEnvKeys.dbName(dbServiceName, databaseName),
237+
true,
238+
getPath('.'));
239+
await EnvUtilities.addProjectVariableKey(projectName, environmentModel, DefaultEnvKeys.dbHost(dbServiceName), true, getPath('.'));
229240
}
230241

231242
private async createProject(config: AddLoopbackConfiguration): Promise<string> {
@@ -240,7 +251,7 @@ export class AddLoopbackCommand extends AddCommand<AddLoopbackConfiguration> {
240251
vscode: false
241252
}
242253
});
243-
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name);
254+
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
244255
await Promise.all([
245256
FsUtilities.rm(getPath(newProject.path, 'src', '__tests__')),
246257
FsUtilities.rm(getPath(newProject.path, GIT_IGNORE_FILE_NAME)),

0 commit comments

Comments
 (0)