Skip to content

Commit

Permalink
[Docs] Complete shell script docs
Browse files Browse the repository at this point in the history
  • Loading branch information
LoicPoullain committed Sep 14, 2024
1 parent 8c9745b commit c841070
Showing 1 changed file with 64 additions and 26 deletions.
90 changes: 64 additions & 26 deletions docs/docs/cli/shell-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@
title: Shell Scripts
---

Shell scripts are an easy way of executing a piece of code from the command line. They can be used in a variety of scenarios and can be a simple code snippet or be more complex and call application services.

Sometimes we have to execute some tasks from the command line. These tasks can serve different purposes such as populating a database (user creation, etc) for instance. They often need to access some of the app classes and functions. This is when shell scripts come into play.
## Structure

## Create Scripts

A shell script is just a TypeScript file located in the `src/scripts`. It must export a `main` function that is then called when running the script.

Let's create a new one with the command line: `npx foal g script display-users`. A new file with a default template should appear in you `src/scripts` directory.

## Write Scripts

Remove the content of `src/scripts/display-users.ts` and replace it with the code below.
A shell script file is divided into two parts: a `main` function, which contains the code to be executed, and a `schema`, which parses and validates the arguments given on the command line and passes them on to the `main` function. The file must be located in the `src/scripts` directory.

*Example: src/scripts/create-user.ts*
```typescript
// 3p
import { Logger, ServiceManager } from '@foal/core';
Expand All @@ -23,40 +17,84 @@ import { Logger, ServiceManager } from '@foal/core';
import { dataSource } from '../db';
import { User } from '../app/entities';

export async function main(args: any, services: ServiceManager, logger: Logger) {
export const schema = {
type: 'object',
properties: {
email: { type: 'string' },
},
required: ['email'],
additionalProperties: false
}

export async function main(args: { email: string }) {
await dataSource.initialize();

try {
const users = await User.find();
const user = new User();
user.email = args.email;

logger.info(`Users: ${JSON.stringify(users, null, 2)}`);
await user.save();
} finally {
dataSource.destroy();
}
}

```

As you can see, we can easily establish a connection to the database in the script as well as import some of the app components (the `User` in this case).

Encapsulating your code in a `main` function without calling it directly in the file has several benefits:
- You can import and test your `main` function in a separate file.
- Using a function lets you easily use async/await keywords when dealing with asynchronous code.
## Generating, Building and Running Shell Scripts

## Build and Run Scripts
To generate a new script, you can use the CLI `generate` command:

To run a script you first need to build it.
```bash
npx foal generate script create-user
# or
npx foal g script create-user
```

```sh
If you need to build the script once, run this command:
```bash
npm run build
```

Then you can execute it with this command:
If you need to build and watch it in dev mode, use this command:
```bash
npm run dev
```

```shell
npx foal run my-script
Then you can run the script as follows:
```bash
npx foal run create-user email=foo@foalts.org
```

> You can also provide additionnal arguments to your script (for example: `npx foal run my-script foo=1 bar='[ 3, 4 ]'`). The default template in the generated scripts shows you how to handle such behavior.
## Accessing Services

If you wish to access a service, you can use the `ServiceManager` instance passed as second argument to the `main` function.

Example

```typescript
import { ServiceManager } from '@foal/core';

import { MyService } from '../app/services';

> If you want your script to recompile each time you save the file, you can run `npm run dev` in a separate terminal.
export function main(args: any, services: ServiceManager) {
const myService = services.get(MyService);

// Do something with myService.
}
```

## Logging

When a script is executed, a script ID is created and added to the log context. Like the request ID in an HTTP request, the script ID is added as a parameter to every log printed during script execution, including any errors. In this way, it is possible to aggregate all logs from a single script execution in a logging program.

If you wish to access the logger in the script, it is passed as the third argument to the main function.

```typescript
import { Logger, ServiceManager } from '@foal/core';


export function main(args: any, services: ServiceManager, logger: Logger) {
logger.info('Hello world!');
}
```

0 comments on commit c841070

Please sign in to comment.