Skip to content

Commit

Permalink
[93] New Docker command to generate DockerFiles of specified services (
Browse files Browse the repository at this point in the history
…#34)

* feat: docker command to generate dockerfiles of services

* fix: updated monitor to monitoring

* fix: updated nest collection

* feat: updated the stencil docker command

* fix: switched to generate command structure

* fix: console table when wrong command is sent

* fix: updated existing unit test and implemented e2e test

* fix: updated test

* feat: Added support for path for A la carte setup

* fix: added the docker command for temporal

* fix: fixed docker flag

* fix: updated test cases for docker command

* fix: updated docker e2e test

* fix: removed logging flags and command

* fix: updated docker command e2e test

* feat: Added Docker command readme

* fix: added minio and fusionauth

* fix: fix the e2e test

* fix: increased the timeout

* fix: updated the docs

* fix: removed comments of logging

* fix: updated readme

* fix: for generation of docker using spec

* fix: updated time for test

---------

Co-authored-by: Yash Mittal <[email protected]>
  • Loading branch information
Savio629 and techsavvyash authored Sep 21, 2024
1 parent a990e90 commit c8cfd32
Show file tree
Hide file tree
Showing 19 changed files with 658 additions and 246 deletions.
73 changes: 73 additions & 0 deletions Docker-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
## Docker Command

```
stencil docker <services...> [options]
stencil do <services...> [options]
```
**Description**

Creates a docker service/container for given command.
- Tooling specific setup
- Creates a folder with the given `<service>` inside docker directory
- À la Carte setup / Adhoc setup
- Creates a docker compose or updates existing docker compose with desired `<service>`

**Arguments**

| Argument | Description |
|-----------|--------------|
| `<service>` | The name of the new project |

**Options**

| Option | Description |
|-----------|--------------|
| `--path [path]` | The path where the docker compose will be generated |


Note: Docker command supports multiple services at a time.

**Services**

- Tooling specific setup


| Name | Alias | Description |
|---|---|---|
| `logging` | `lg` | Generates a docker service for logging |
| `monitoringService` |`ms` | Generates a docker service for monitoring |
| `temporal` | `tp` | Generates a docker service for temporal |

- À la Carte setup / Adhoc setup


| Name | Alias | Description |
|---|---|---|
| `postgres` | `pg` | Generate a docker compose for postgres |
| `hasura` |`hs` | Generate a docker compose for hasura |
| `minio` |`mi` | Generate a docker compose for minio |
| `fusionauth` |`fa` | Generate a docker compose for fusionauth |


## How to include new docker services ?

**Stencil-cli**

1. Include the docker service in `lib/schematics/nest.collection.ts` with its name, alias and description.

**Schematics**
1. Create a folder inside of **schematics** package under `src/lib/docker/nameOfDockerService`
2. If the dockerService is a tooling setup then refer existing tooling setups such as temporal,monitoringService, logging.
- Create `src/lib/docker/files/ts/nameOfDockerService` and paste all the necessary files needed to be generated when the service is called.
- Create factory file, schema file and interface of the dockerService inside `src/lib/docker/nameOfDockerService` by refering existing tooling setup.
3. If the dockerService is a adhoc setup then refer existing adhoc setup such as postgres, hasura.
- Create factory file, schema file and interface of the dockerService inside `src/lib/docker/nameOfDockerService` by refering existing adhoc setup.
- Paste the `docker-compose` and `.env` content inside of factory file refering existing adhoc setup.

## Which files will be changed/updated?

**Tooling setup**
- Basically whenever tooling setup is generated eg. `stencil docker temporal` , `docker/temporal` will be created.

**Adhoc Setup**
- Whenever adhoc setup is generated eg. `stencil docker postgres` , then` docker-compose`, `.env` and `docker-start.sh` is generated/updated.
96 changes: 96 additions & 0 deletions actions/docker.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
AbstractPackageManager,
PackageManagerFactory,
} from '../lib/package-managers';
import { AbstractCollection, Collection, CollectionFactory, SchematicOption,} from '../lib/schematics';
import { AbstractAction } from './abstract.action';
import { Input } from '../commands';
import * as chalk from 'chalk';
import * as fs from 'fs';
import * as yaml from 'js-yaml';
import { join } from 'path';

export class DockerAction extends AbstractAction {
private manager!: AbstractPackageManager;
public async handle(commandInputs: Input[],options: Input[]) {
this.manager = await PackageManagerFactory.find();

const serviceName = commandInputs[0].value as string;

const specFilePath = await this.getSpecFilePath();

if (specFilePath) {
await this.updateSpecFile(specFilePath, serviceName);
}

const collection: AbstractCollection = CollectionFactory.create(
Collection.NESTJS,
);
const schematicOptions: SchematicOption[] = this.mapSchematicOptions(commandInputs);
schematicOptions.push(
new SchematicOption('language', 'ts'),
);
const path = options.find((option) => option.name === 'path')!.value as string;
schematicOptions.push(new SchematicOption('path', path));
try {
await collection.execute(commandInputs[0].value as string, schematicOptions,'docker');
}catch(error){
if (error && error.message) {
console.error(chalk.red(error.message));
}
}
}
private async getSpecFilePath(): Promise<string | null> {
try {
const nestCliConfig = await fs.promises.readFile('nest-cli.json', 'utf-8');
const config = JSON.parse(nestCliConfig);
if (config.specFile) {
return config.specFile;
} else {
return null;
}
} catch (error) {
console.error(chalk.red('Error reading nest-cli.json'), error);
return null;
}
}

private async updateSpecFile(specFilePath: string, serviceName: string): Promise<boolean> {
try {
const specFileFullPath = join(process.cwd(), specFilePath);
const specFileContent = await fs.promises.readFile(specFileFullPath, 'utf-8');
const spec = yaml.load(specFileContent) as any;

if (!spec.docker) {
spec.docker = [];
}

let updated = false;
if (!spec.docker.includes(serviceName)) {
spec.docker.push(serviceName);
updated = true;
}

if (updated) {
const updatedYaml = yaml.dump(spec);
await fs.promises.writeFile(specFileFullPath, updatedYaml, 'utf-8');
}

return updated;
} catch (error) {
console.error(chalk.red('Error reading or updating spec.yaml'), error);
return false;
}
}

private mapSchematicOptions = (inputs: Input[]): SchematicOption[] => {
const excludedInputNames = ['path','schematic', 'spec', 'flat', 'specFileSuffix'];
const options: SchematicOption[] = [];
inputs.forEach((input) => {
if (!excludedInputNames.includes(input.name) && input.value !== undefined) {
options.push(new SchematicOption(input.name, input.value));
}
});
return options;
};
}
2 changes: 1 addition & 1 deletion actions/generate.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ const generateFiles = async (inputs: Input[]) => {
if (!schematicInput) {
throw new Error('Unable to find a schematic for this configuration');
}
await collection.execute(schematicInput.value as string, schematicOptions);
await collection.execute(schematicInput.value as string, schematicOptions, 'schematic');
} catch (error) {
if (error && error.message) {
console.error(chalk.red(error.message));
Expand Down
1 change: 1 addition & 0 deletions actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './list.action';
export * from './new.action';
export * from './start.action';
export * from './add.action';
export * from './docker.action';
Loading

0 comments on commit c8cfd32

Please sign in to comment.