Skip to content

Commit

Permalink
Merge pull request #1292 from FoalTS/shell-script-services
Browse files Browse the repository at this point in the history
Provide a ServiceManager to shell scripts
  • Loading branch information
LoicPoullain authored Aug 26, 2024
2 parents bdf395c + 7692b0a commit 56c0a81
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 26 deletions.
10 changes: 10 additions & 0 deletions docs/blog/version-5.0-release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ Version 5.0 of [Foal](https://foalts.org/) is out!
- The `Logger.addLogContext(key, value)` method now accepts a record as parameter: `Logger.addLogContext(context)`. This makes the function's signature more consistent with other logging methods (`info`, `warn`, etc.) and allows multiple keys/values to be passed at once.
- The deprecated `settings.loggerFormat` configuration has been removed. If you want to disable HTTP logging, set `settings.logger.logHttpRequests` to false instead.
## Shell scripts
- The `main` function of shell scripts now receives an instance of `ServiceManager` as second argument:
```typescript
export async function main(args: any, services: ServiceManager) {
// ...
}
```
## Removal of deprecated components
- The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead.
Expand Down
12 changes: 6 additions & 6 deletions docs/docs/authentication/session-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ npx foal g script revoke-session
Open `scripts/revoke-session.ts` and update its content.

```typescript
import { createService, readSession, Store } from '@foal/core';
import { readSession, ServiceManager, Store } from '@foal/core';

import { dataSource } from '../db';

Expand All @@ -653,10 +653,10 @@ export const schema = {
required: [ 'token' ]
}

export async function main({ token }: { token: string }) {
export async function main({ token }: { token: string }, services: ServiceManager) {
await dataSource.initialize();

const store = createService(Store);
const store = services.get(Store);
await store.boot();

const session = await readSession(store, token);
Expand Down Expand Up @@ -687,14 +687,14 @@ npx foal g script revoke-all-sessions
Open `scripts/revoke-all-sessions.ts` and update its content.

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

import { dataSource } from '../db';

export async function main() {
export async function main(args: any, services: ServiceManager) {
await dataSource.initialize();

const store = createService(Store);
const store = services.get(Store);
await store.boot();
await store.clear();
}
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/cli/shell-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ Remove the content of `src/scripts/display-users.ts` and replace it with the cod

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

// App
import { dataSource } from '../db';
import { User } from '../app/entities';
import { Logger } from '../app/services';

export async function main() {
export async function main(args: any, services: ServiceManager) {
await dataSource.initialize();

try {
const users = await User.find();
const logger = createService(Logger);
const logger = services.get(Logger);
logger.log(users);
} finally {
dataSource.destroy();
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

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

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { notStrictEqual, strictEqual } from 'assert';
import { DataSource } from 'typeorm';

// FoalTS
import { Config, createService, createSession, readSession, Store } from '@foal/core';
import { Config, createSession, readSession, ServiceManager, Store } from '@foal/core';
import { DatabaseSession } from '@foal/typeorm';
import { createAndInitializeDataSource, getTypeORMStorePath } from '../../../common';

Expand All @@ -28,10 +28,10 @@ describe('Feature: Revoking sessions', () => {

/* ======================= DOCUMENTATION BEGIN ======================= */

async function main({ token }: { token: string }) {
async function main({ token }: { token: string }, services: ServiceManager) {
// await dataSource.initialize();

const store = createService(Store);
const store = services.get(Store);
await store.boot();

const session = await readSession(store, token);
Expand All @@ -42,7 +42,8 @@ describe('Feature: Revoking sessions', () => {

/* ======================= DOCUMENTATION END ========================= */

const store = createService(Store);
const services = new ServiceManager();
const store = services.get(Store);

dataSource = await createAndInitializeDataSource([ DatabaseSession ]);

Expand All @@ -51,7 +52,7 @@ describe('Feature: Revoking sessions', () => {

notStrictEqual(await readSession(store, session.getToken()), null);

await main({ token: session.getToken() });
await main({ token: session.getToken() }, services);

strictEqual(await readSession(store, session.getToken()), null);

Expand All @@ -61,17 +62,18 @@ describe('Feature: Revoking sessions', () => {

/* ======================= DOCUMENTATION BEGIN ======================= */

async function main() {
async function main(args: any, services: ServiceManager) {
// await dataSource.initialize();

const store = createService(Store);
const store = services.get(Store);
await store.boot();
await store.clear();
}

/* ======================= DOCUMENTATION END ========================= */

const store = createService(Store);
const services = new ServiceManager();
const store = services.get(Store);

dataSource = await createAndInitializeDataSource([ DatabaseSession ]);

Expand All @@ -83,7 +85,7 @@ describe('Feature: Revoking sessions', () => {
notStrictEqual(await readSession(store, session.getToken()), null);
notStrictEqual(await readSession(store, session2.getToken()), null);

await main();
await main(undefined, services);

strictEqual(await readSession(store, session.getToken()), null);
strictEqual(await readSession(store, session2.getToken()), null);
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"commander": "~12.1.0"
},
"devDependencies": {
"@foal/core": "^4.5.0",
"@types/mocha": "10.0.7",
"@types/node": "20.14.8",
"copyfiles": "~2.4.1",
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/generate/specs/script/test-foo-bar.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ServiceManager } from '@foal/core';

export const schema = {
additionalProperties: false,
properties: {
Expand All @@ -9,6 +11,6 @@ export const schema = {
type: 'object',
};

export async function main(args: any) {
export async function main(args: any, services: ServiceManager) {

}
4 changes: 3 additions & 1 deletion packages/cli/src/generate/templates/script/script.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ServiceManager } from '@foal/core';

export const schema = {
additionalProperties: false,
properties: {
Expand All @@ -9,6 +11,6 @@ export const schema = {
type: 'object',
};

export async function main(args: any) {
export async function main(args: any, services: ServiceManager) {

}
32 changes: 32 additions & 0 deletions packages/cli/src/run/run-script.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,38 @@ describe('runScript', () => {
});
});

it('should call the "main" function of build/scripts/my-script.js with a ServiceManager.', async () => {
mkdirIfDoesNotExist('build/scripts');
const scriptContent = `const { writeFileSync } = require('fs');
const { ServiceManager } = require('@foal/core');
module.exports.main = function main(args, services) {
const isServiceManager = services instanceof ServiceManager;
writeFileSync('my-script-temp', JSON.stringify({
isServiceManager
}), 'utf8');
}`;
writeFileSync('build/scripts/my-script.js', scriptContent, 'utf8');

delete require.cache[join(process.cwd(), `./build/scripts/my-script.js`)];

await runScript({ name: 'my-script' }, [
'/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/node',
'/Users/loicpoullain/.nvm/versions/node/v8.11.3/bin/foal',
'run',
'my-script',
'foo=bar',
]);

if (!existsSync('my-script-temp')) {
throw new Error('The script was not executed');
}
const actual = JSON.parse(readFileSync('my-script-temp', 'utf8'));

deepStrictEqual(actual, {
isServiceManager: true,
});
});

it('should catch and log errors thrown in the "main" function.', async () => {
mkdirIfDoesNotExist('build/scripts');
const scriptContent = `const { writeFileSync } = require('fs');
Expand Down
13 changes: 10 additions & 3 deletions packages/cli/src/run/run-script.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// std
import { existsSync } from 'fs';
import { join } from 'path';

// 3p
import Ajv from 'ajv';
Expand All @@ -10,6 +9,12 @@ import addFormats from 'ajv-formats';
import { getCommandLineArguments } from './get-command-line-arguments.util';

export async function runScript({ name }: { name: string }, argv: string[], log = console.log) {
const { ServiceManager } = require(require.resolve('@foal/core', {
paths: [ process.cwd() ],
})) as typeof import('@foal/core');

const services = new ServiceManager();

if (!existsSync(`build/scripts/${name}.js`)) {
if (existsSync(`src/scripts/${name}.ts`)) {
log(
Expand All @@ -22,7 +27,9 @@ export async function runScript({ name }: { name: string }, argv: string[], log
return;
}

const { main, schema } = require(join(process.cwd(), `./build/scripts/${name}`));
const { main, schema } = require(require.resolve(`./build/scripts/${name}`, {
paths: [ process.cwd() ],
}));

if (!main) {
log(`Error: No "main" function was found in build/scripts/${name}.js.`);
Expand All @@ -47,7 +54,7 @@ export async function runScript({ name }: { name: string }, argv: string[], log
}

try {
await main(args);
await main(args, services);
} catch (error: any) {
log(error);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/examples/src/scripts/revoke-token.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// 3p
import { createService } from '@foal/core';
import { ServiceManager } from '@foal/core';
import { TypeORMStore } from '@foal/typeorm';

// App
Expand All @@ -14,8 +14,8 @@ export const schema = {
type: 'object',
};

export async function main({ token }: { token: string }) {
export async function main({ token }: { token: string }, services: ServiceManager) {
await dataSource.initialize();

await createService(TypeORMStore).destroy(token);
await services.get(TypeORMStore).destroy(token);
}

0 comments on commit 56c0a81

Please sign in to comment.