Add command to update serverless layer (#11500)
New command to add packages to serverless -> Run into your terminal `npx nx run twenty-server:command serverless:add-packages -p stripe@17.0.0,@slack/web-api,@slack/oauth` Will create a new layer folder, add packages in it and update the new last_layer_version <img width="1468" alt="image" src="https://github.com/user-attachments/assets/da8ee77f-e512-4ceb-95bc-cfa979f3439c" /> Before <img width="877" alt="image" src="https://github.com/user-attachments/assets/35f6bb6c-2ebf-46fe-bd15-4e6352901fc8" /> After <img width="938" alt="image" src="https://github.com/user-attachments/assets/785af132-5e8c-4a9a-bc57-dffdcaaeec02" />
This commit is contained in:
@ -0,0 +1,135 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
|
|
||||||
|
import * as fs from 'fs/promises';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
|
import { Command, CommandRunner, Option } from 'nest-commander';
|
||||||
|
|
||||||
|
const execPromise = promisify(exec);
|
||||||
|
|
||||||
|
@Command({
|
||||||
|
name: 'serverless:add-packages',
|
||||||
|
description:
|
||||||
|
'Create a new serverless layer version and install packages in it',
|
||||||
|
})
|
||||||
|
export class AddPackagesCommand extends CommandRunner {
|
||||||
|
private readonly logger = new Logger(AddPackagesCommand.name);
|
||||||
|
|
||||||
|
@Option({
|
||||||
|
flags: '-p, --packages <packages>',
|
||||||
|
description: 'comma separated packages (eg: axios,uuid@9.0.1)',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
parsePackages(val: string): string[] {
|
||||||
|
return val.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(
|
||||||
|
passedParams: string[],
|
||||||
|
options: Record<string, any>,
|
||||||
|
): Promise<void> {
|
||||||
|
this.logger.log('---------------------------------------');
|
||||||
|
this.logger.warn('This command should be run locally only');
|
||||||
|
this.logger.log('');
|
||||||
|
|
||||||
|
const layersFolder = this.getAbsoluteFilePath(
|
||||||
|
`src/engine/core-modules/serverless/drivers/layers`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentVersion = await this.getLastLayerVersion();
|
||||||
|
|
||||||
|
const newVersion = currentVersion + 1;
|
||||||
|
|
||||||
|
const currentVersionFolder = `${layersFolder}/${currentVersion}`;
|
||||||
|
const newVersionFolder = `${layersFolder}/${newVersion}`;
|
||||||
|
|
||||||
|
await fs.cp(currentVersionFolder, newVersionFolder, { recursive: true });
|
||||||
|
|
||||||
|
// Install each package
|
||||||
|
this.logger.log('Installing packages');
|
||||||
|
await this.installPackages(options.packages, newVersionFolder);
|
||||||
|
|
||||||
|
this.logger.log('Cleaning');
|
||||||
|
await this.cleanPackageInstallation(newVersionFolder);
|
||||||
|
|
||||||
|
this.logger.log('Updating last layer version');
|
||||||
|
await this.updateLastLayerVersion(newVersion);
|
||||||
|
|
||||||
|
this.logger.log('Add changes to git');
|
||||||
|
await this.addToGit(layersFolder);
|
||||||
|
|
||||||
|
this.logger.log('');
|
||||||
|
this.logger.log(
|
||||||
|
`New packages '${options.packages.join("', '")}' installed in new layer version '${newVersion}' `,
|
||||||
|
);
|
||||||
|
this.logger.log('Please commit your changes');
|
||||||
|
this.logger.log('---------------------------------------');
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAbsoluteFilePath(path: string) {
|
||||||
|
const rootPath = process.cwd();
|
||||||
|
|
||||||
|
return resolve(rootPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addToGit(folderPath: string) {
|
||||||
|
await execPromise(`git add ${folderPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async cleanPackageInstallation(folderPath: string) {
|
||||||
|
await fs.rm(folderPath + '/node_modules', {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
await fs.rm(folderPath + '/.yarn', {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async installPackages(packages: string[], folderPath: string) {
|
||||||
|
if (packages?.length) {
|
||||||
|
for (const packageName of packages) {
|
||||||
|
this.logger.log(`- adding '${packageName}'...`);
|
||||||
|
try {
|
||||||
|
await execPromise(`yarn add ${packageName}`, {
|
||||||
|
cwd: folderPath,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`Failed to install ${packageName}: ${(error as Error).message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getLastLayerVersion() {
|
||||||
|
const filePath = this.getAbsoluteFilePath(
|
||||||
|
'src/engine/core-modules/serverless/drivers/layers/last-layer-version.ts',
|
||||||
|
);
|
||||||
|
|
||||||
|
const content = await fs.readFile(filePath, 'utf8');
|
||||||
|
const match = content.match(/export const LAST_LAYER_VERSION = (\d+);/);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
throw new Error('LAST_LAYER_VERSION not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseInt(match[1], 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateLastLayerVersion(newVersion: number) {
|
||||||
|
const filePath = this.getAbsoluteFilePath(
|
||||||
|
'src/engine/core-modules/serverless/drivers/layers/last-layer-version.ts',
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.writeFile(
|
||||||
|
filePath,
|
||||||
|
`export const LAST_LAYER_VERSION = ${newVersion};\n`,
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import {
|
|||||||
ServerlessModuleAsyncOptions,
|
ServerlessModuleAsyncOptions,
|
||||||
} from 'src/engine/core-modules/serverless/serverless.interface';
|
} from 'src/engine/core-modules/serverless/serverless.interface';
|
||||||
import { ServerlessService } from 'src/engine/core-modules/serverless/serverless.service';
|
import { ServerlessService } from 'src/engine/core-modules/serverless/serverless.service';
|
||||||
|
import { AddPackagesCommand } from 'src/engine/core-modules/serverless/commands/add-packages.command';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
export class ServerlessModule {
|
export class ServerlessModule {
|
||||||
@ -27,7 +28,7 @@ export class ServerlessModule {
|
|||||||
return {
|
return {
|
||||||
module: ServerlessModule,
|
module: ServerlessModule,
|
||||||
imports: options.imports || [],
|
imports: options.imports || [],
|
||||||
providers: [ServerlessService, provider],
|
providers: [ServerlessService, provider, AddPackagesCommand],
|
||||||
exports: [ServerlessService],
|
exports: [ServerlessService],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user