@mondaycom/apps-cli
Version:
A cli tool to manage apps (and monday-code projects) in monday.com
113 lines (112 loc) • 4.99 kB
JavaScript
import * as path from 'node:path';
import { Args, Flags } from '@oclif/core';
import { Listr } from 'listr2';
import { BaseCommand } from '../../commands-base/base-command.js';
import { PROJECT_TEMPLATES } from '../../consts/scaffold.js';
import { PromptService } from '../../services/prompt-service.js';
import { downloadTemplateTask, editEnvFileTask, installDependenciesTask, openSetupFileTask, runProjectTask, validateDestination, } from '../../services/scaffold-service.js';
import logger from '../../utils/logger.js';
export default class AppScaffold extends BaseCommand {
static description = 'Scaffold a monday app from a template, install dependencies, and start the project automatically.';
static examples = [
'<%= config.bin %> <%= command.id %>',
'<%= config.bin %> <%= command.id %> ./my-app quickstart-react',
'<%= config.bin %> <%= command.id %> ./my-app slack-node --signingSecret YOUR_SECRET',
'<%= config.bin %> <%= command.id %> ./my-app word-cloud --command dev',
];
static args = {
destination: Args.string({
description: 'The destination directory for the scaffolded project',
required: false,
}),
project: Args.string({
description: 'The name of the template project to scaffold',
required: false,
}),
};
static flags = AppScaffold.serializeFlags({
signingSecret: Flags.string({
char: 's',
description: 'monday signing secret (for .env configuration)',
required: false,
}),
command: Flags.string({
char: 'c',
description: 'npm script command to run after installation (default: start)',
required: false,
default: 'start',
}),
});
DEBUG_TAG = 'app_scaffold';
async run() {
try {
const { args, flags } = await this.parse(AppScaffold);
// Get project
let project;
if (args.project) {
const foundProject = PROJECT_TEMPLATES.find(p => p.name === args.project);
if (!foundProject) {
throw new Error(`Project "${args.project}" not found. Available projects: ${PROJECT_TEMPLATES.map(p => p.name).join(', ')}`);
}
project = foundProject;
}
else {
const projectName = await PromptService.promptList('Which project do you want to start from?', PROJECT_TEMPLATES.map(p => p.name));
project = PROJECT_TEMPLATES.find(p => p.name === projectName);
}
// Get destination
let destination;
if (args.destination) {
destination = path.resolve(args.destination);
}
else {
const destInput = await PromptService.promptInput('Choose destination folder', false);
destination = path.resolve(destInput || './');
}
// Validate destination
await validateDestination(destination);
// Get signing secret if needed
let signingSecret = flags.signingSecret;
if (!signingSecret && project.isWithSigningSecret) {
signingSecret = await PromptService.promptInput('Enter signing secret (optional, press Enter to skip)', false, true);
}
const projectPath = path.join(destination, project.name);
// Use command flag (defaults to 'start')
const startCommand = flags.command;
this.preparePrintCommand(this, flags, args);
const context = {
project,
destination,
signingSecret,
projectPath,
startCommand,
};
await this.executeScaffold(context);
}
catch (error) {
logger.debug(error, this.DEBUG_TAG);
throw error;
}
}
async executeScaffold(ctx) {
const tasks = new Listr([
{ title: 'Downloading template', task: downloadTemplateTask },
{ title: 'Configuring environment', task: editEnvFileTask },
{
title: 'Opening setup documentation',
task: openSetupFileTask,
enabled: () => Boolean(ctx.project.openSetupMd),
},
{ title: 'Installing dependencies', task: installDependenciesTask },
{ title: 'Starting project', task: runProjectTask },
]);
await tasks.run(ctx);
logger.success(`Project is running at: ${ctx.projectPath}\n` +
`To run manually later:\n` +
` cd ${ctx.project.name}\n` +
` npm run ${ctx.startCommand}\n\n` +
`Press Enter to provide your access token and view the tunnel URL\n`);
// Keep scaffold process alive so dev server continues running
await new Promise(() => { });
}
}