@corva/create-app 0.49.0-0 → 0.49.0-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ import { Command } from 'commander';
2
+ import { runFlow } from '../flow.js';
3
+ import { ATTACH_FLOW } from '../flows/attach.js';
4
+ import { getRealWorkingDir } from '../helpers/commands.js';
5
+ import { apiKeyOption } from '../options/api-key.js';
6
+ import { appVersion } from '../options/app-version.js';
7
+ import { envOption } from '../options/env.js';
8
+ import { originalCwdOption } from '../options/original-cwd.js';
9
+ import { silentOption } from '../options/silent.js';
10
+
11
+ export const attachCommand = new Command('attach')
12
+ .description('Add app to live assets streams')
13
+ .argument('<project-directory>', 'Project directory to work with')
14
+ .addOption(apiKeyOption)
15
+ .addOption(envOption)
16
+ .addOption(silentOption)
17
+ .addOption(appVersion)
18
+ .addOption(originalCwdOption)
19
+ .action(async (dirName, options) => {
20
+ await runFlow(ATTACH_FLOW, { dirName: getRealWorkingDir(dirName, options), options });
21
+ });
@@ -0,0 +1,424 @@
1
+ import { dirname, join, resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { clear } from 'node:console';
4
+ import os from 'node:os';
5
+ import { existsSync } from 'node:fs';
6
+
7
+ import { Command, Option } from 'commander';
8
+ import spawn from 'cross-spawn';
9
+ import chalk from 'chalk';
10
+ import fs from 'fs-extra';
11
+ import figlet from 'figlet';
12
+ import _ from 'lodash/fp.js';
13
+ import inquirer from 'inquirer';
14
+
15
+ import { originalCwdOption } from '../options/original-cwd.js';
16
+ import { ensureBumpVersion, ensureLatestVersion } from '../helpers/cli-version.js';
17
+ import { logger } from '../helpers/logger.js';
18
+ import { IS_WINDOWS, resolveAppRuntime } from '../helpers/resolve-app-runtime.js';
19
+ import { initVersioning } from '../helpers/versioning.js';
20
+ import { copyFolderRecursiveSync, putVariablesInEnvFile } from '../helpers/utils.js';
21
+ import { getDefaultsForPackageJson } from '../constants/package.js';
22
+ import { getRealWorkingDir } from '../helpers/commands.js';
23
+ import { Manifest } from '../flows/lib/manifest.js';
24
+ import { fillManifest } from '../helpers/manifest.js';
25
+ import { getManifestMandatoryKeys, manifestOptions } from '../constants/manifest.js';
26
+
27
+ const __filename = fileURLToPath(import.meta.url);
28
+ const __dirname = dirname(__filename);
29
+
30
+ const WRITE_TO_JSON_OPTS = {
31
+ spaces: 2,
32
+ EOL: os.EOL,
33
+ };
34
+
35
+ export const createCommand = new Command('create')
36
+ .description('Create a new app')
37
+ .argument('[project-directory]', 'project directory to work with', process.argv[process.argv.length - 1])
38
+ .addOption(originalCwdOption)
39
+ .usage(`${chalk.green('<project-directory>')} [options]`);
40
+
41
+ manifestOptions().forEach((value) => {
42
+ const type = typeof value.default;
43
+ const cliType = type === 'undefined' ? (value.choices ? ' [string]' : '') : ` [${type}]`;
44
+ const alias = value.alias ? `-${value.alias}, ` : '';
45
+ const optionString = `${alias}--${value.name}${cliType}`;
46
+
47
+ const option = new Option(optionString, value.message);
48
+
49
+ if (value.choices) {
50
+ if (typeof value.choices === 'function') {
51
+ option.choices(value.choices());
52
+ } else {
53
+ option.choices(value.choices.map((choice) => `${typeof choice === 'object' ? choice.value : choice}`));
54
+ }
55
+ }
56
+
57
+ if (type === 'number') {
58
+ option.argParser(Number);
59
+ }
60
+
61
+ if (type !== 'undefined') {
62
+ option.default(value.default);
63
+ }
64
+
65
+ createCommand.addOption(option);
66
+ });
67
+
68
+ createCommand.version(fs.readJSONSync(join(__dirname, '../../package.json')).version);
69
+
70
+ createCommand.action(async (dirName, options) => {
71
+ if (options.zip || options.release) {
72
+ options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
73
+ }
74
+
75
+ startingMessage();
76
+
77
+ // NOTE: Default action
78
+ await createApp(dirName, options);
79
+ });
80
+
81
+ /**
82
+ *
83
+ * @param {import('./flows/lib/manifest').Manifest} manifest
84
+ */
85
+ const getEnvManagementLink = (manifest) => {
86
+ if (manifest.isJs()) {
87
+ if (IS_WINDOWS) {
88
+ return 'https://github.com/coreybutler/nvm-windows';
89
+ }
90
+
91
+ return 'https://github.com/nvm-sh/nvm';
92
+ }
93
+
94
+ if (IS_WINDOWS) {
95
+ return 'https://github.com/pyenv-win/pyenv-win';
96
+ }
97
+
98
+ return 'https://github.com/pyenv/pyenv';
99
+ };
100
+
101
+ async function initPackage(projectName, opts) {
102
+ const manifest = new Manifest(fillManifest(opts));
103
+ const runtime = resolveAppRuntime(opts);
104
+
105
+ if (!(await runtime.isRuntimeAvailable())) {
106
+ throw new Error(
107
+ `Runtime "${opts.runtime}" is not available locally. Please proceed to ${chalk.green(
108
+ getEnvManagementLink(manifest),
109
+ )} to install it locally.`,
110
+ );
111
+ }
112
+
113
+ if (manifest.isUi()) {
114
+ await ensureLatestVersion();
115
+ }
116
+
117
+ const root = getRealWorkingDir(projectName, opts);
118
+
119
+ logger.log(`Creating a new Corva app in ${chalk.green(root)}.`);
120
+
121
+ await fs.ensureDir(root);
122
+
123
+ if ((await fs.readdir(root)).length) {
124
+ const shouldCleanup = await inquirer
125
+ .prompt([
126
+ {
127
+ message: `Directory "${root}" is not empty. Clean it to proceed?`,
128
+ name: 'cleanup',
129
+ type: 'confirm',
130
+ },
131
+ ])
132
+ .then(_.get('cleanup'));
133
+
134
+ if (shouldCleanup) {
135
+ await fs.emptyDir(root);
136
+ } else {
137
+ throw new Error(`Directory is not empty: ${root}`);
138
+ }
139
+ }
140
+
141
+ await fs.writeJSON(join(root, 'manifest.json'), manifest.manifest, WRITE_TO_JSON_OPTS);
142
+
143
+ await addTemplate(root, manifest, runtime);
144
+ await configureApp(root, manifest, runtime);
145
+
146
+ opts.dependenciesInstall && (await installDependencies(root, manifest, runtime));
147
+
148
+ opts.gitInit && (await initVersioning(root, manifest, runtime));
149
+
150
+ logger.log();
151
+ logger.log(`Success! Created ${chalk.green(manifest.name)} at ${chalk.yellow(root)}`);
152
+
153
+ helpCommands(manifest, runtime);
154
+
155
+ logger.log();
156
+ }
157
+
158
+ async function createApp(dirName, opts) {
159
+ const { isValid, values } = checkOptions(opts);
160
+
161
+ if (isValid) {
162
+ Object.keys(values).forEach((key) => {
163
+ logger.log(`${key} : ${values[key]}`);
164
+ });
165
+
166
+ return initPackage(dirName, opts);
167
+ }
168
+
169
+ console.log('Please fill your app Metadata');
170
+
171
+ const answers = await inquirer.prompt(manifestOptions(dirName), opts);
172
+
173
+ return initPackage(dirName, answers);
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @param {string} root
179
+ * @param {import('./flows/lib/manifest').Manifest} manifest
180
+ * @param {*} runtime
181
+ */
182
+ async function addTemplate(root, manifest, runtime) {
183
+ logger.log(chalk.green('Copying app template...'));
184
+ logger.log();
185
+
186
+ const cliRoot = resolve(__dirname, '..', '..');
187
+
188
+ const templateFolder = join(cliRoot, 'templates', manifest.templateName, runtime.language);
189
+
190
+ copyFolderRecursiveSync(templateFolder, root);
191
+
192
+ if (manifest.isNode()) {
193
+ copyFolderRecursiveSync(join(cliRoot, 'common', 'node'), root);
194
+ }
195
+
196
+ if (manifest.isPython()) {
197
+ copyFolderRecursiveSync(join(cliRoot, 'common', 'python'), root);
198
+ }
199
+
200
+ if (!manifest.isUi()) {
201
+ await putVariablesInEnvFile(root, manifest);
202
+ }
203
+
204
+ // We can't have .gitignore file in our templates.
205
+ // It's missing when @corva/create-app is installed.
206
+ // That's why we manually rename gitignore to .gitignore after copying template
207
+ const targetGitignore = join(root, '.gitignore');
208
+
209
+ fs.renameSync(join(root, 'gitignore'), targetGitignore);
210
+
211
+ if (runtime.language === 'typescript' && manifest.isNode()) {
212
+ await fs.appendFile(targetGitignore, '\n**/*.js\n');
213
+ }
214
+
215
+ logger.log(chalk.green('Done: copying app template!'));
216
+ }
217
+
218
+ /**
219
+ *
220
+ * @param {string} root
221
+ * @param {import('./flows/lib/manifest').Manifest} manifest
222
+ * @param {*} runtime
223
+ */
224
+ async function configureApp(root, manifest, runtime) {
225
+ if (manifest.isJs()) {
226
+ await addNvmRc(root, manifest, runtime);
227
+ await addPackageJSON(root, manifest, runtime);
228
+ }
229
+
230
+ if (manifest.isNode()) {
231
+ await addTsConfigs(root, manifest, runtime);
232
+ }
233
+
234
+ if (manifest.isPython()) {
235
+ await addPythonConfigs(root, manifest, runtime);
236
+ }
237
+ }
238
+
239
+ const addNvmRc = async (root, manifest, runtime) => {
240
+ await fs.outputFile(join(root, '.nvmrc'), `${runtime.semver}\n`);
241
+ };
242
+
243
+ /**
244
+ *
245
+ * @param {string} root
246
+ * @param {Manifest} manifest
247
+ * @param {import('./helpers/resolve-app-runtime.js').Runtime} runtime
248
+ */
249
+ const addPythonConfigs = async (root, manifest, runtime) => {
250
+ await fs.writeFile(resolve(root, '.python-version'), `${runtime.semver}\n`);
251
+ await fs.writeFile(resolve(root, '.python-virtualenv'), `${manifest.unix_name}\n`);
252
+ };
253
+
254
+ const addTsConfigs = (root, manifest, runtime) => {
255
+ if (runtime.language !== 'typescript') {
256
+ return;
257
+ }
258
+
259
+ return Promise.all([
260
+ fs.writeJson(
261
+ resolve(root, 'tsconfig.json'),
262
+ {
263
+ extends: `@tsconfig/node${runtime.version}/tsconfig.json`,
264
+ compilerOptions: {
265
+ inlineSourceMap: true,
266
+ strict: false,
267
+ },
268
+ },
269
+ WRITE_TO_JSON_OPTS,
270
+ ),
271
+ fs.writeJson(
272
+ resolve(root, 'tsconfig.build.json'),
273
+ {
274
+ extends: './tsconfig.json',
275
+ include: ['lib/**/*.ts', 'index.ts'],
276
+ exclude: ['node_modules', '**/*.spec.ts'],
277
+ },
278
+ WRITE_TO_JSON_OPTS,
279
+ ),
280
+ ]);
281
+ };
282
+
283
+ /**
284
+ *
285
+ * @param {string} root
286
+ * @param {import('./flows/lib/manifest').Manifest} manifest
287
+ */
288
+ function addPackageJSON(root, manifest, runtime) {
289
+ const {
290
+ version,
291
+ description,
292
+ scripts,
293
+ dependencies,
294
+ devDependencies,
295
+ main,
296
+ license = 'UNLICENSED',
297
+ private: isPrivate = true,
298
+ ...rest
299
+ } = getDefaultsForPackageJson(manifest, runtime);
300
+
301
+ const packageJson = {
302
+ name: manifest.unix_name,
303
+ version,
304
+ description: manifest.description || description,
305
+ main,
306
+ private: isPrivate,
307
+ license,
308
+ engines: {
309
+ node: `^${runtime.version}`,
310
+ [runtime.packageManager]: '*',
311
+ },
312
+ scripts,
313
+ dependencies,
314
+ devDependencies,
315
+ ...rest,
316
+ };
317
+
318
+ return fs.writeJSON(join(root, 'package.json'), packageJson, WRITE_TO_JSON_OPTS);
319
+ }
320
+
321
+ /**
322
+ * @param {string} root
323
+ * @param {import('./flows/lib/manifest').Manifest} manifest
324
+ * @param {import('./helpers/resolve-app-runtime.js').Runtime} runtime
325
+ * @returns {Promise<void>}
326
+ * @throws {Error}
327
+ * @throws {import('child_process').ExecException}
328
+ * @throws {import('child_process').SpawnSyncReturns<Buffer>}
329
+ */
330
+ async function installDependencies(root, manifest, runtime) {
331
+ const command = manifest.isJs() ? runtime.packageManager : 'make';
332
+
333
+ if (IS_WINDOWS && !manifest.isJs()) {
334
+ logger.log();
335
+ logger.log(`⚠️ ${chalk.yellow('Please install project dependencies manually')}`);
336
+
337
+ return;
338
+ }
339
+
340
+ const args = ['install'];
341
+ const opts = { stdio: ['inherit', 'inherit', 'pipe'], cwd: root };
342
+
343
+ if (process.env.CI && command === 'yarn') {
344
+ args.push('--cache-folder=".yarn-cache"');
345
+ }
346
+
347
+ logger.log(chalk.yellow(`Installing template dependencies using ${runtime.packageManager}...`));
348
+
349
+ const nvmOpts = {
350
+ shell: true,
351
+ ...opts,
352
+ };
353
+
354
+ const proc =
355
+ manifest.isJs() && existsSync(`${os.homedir()}/.nvm/nvm.sh`)
356
+ ? spawn.sync(`\\. ${os.homedir()}/.nvm/nvm.sh && nvm i && ${command} ${args.join(' ')}`, nvmOpts)
357
+ : spawn.sync(command, args, opts);
358
+
359
+ if (proc.stderr) {
360
+ const error = proc.stderr
361
+ .toString('utf8')
362
+ .split('\n')
363
+ // NOTE: filter out warnings caused by @corva/ui peer dependencies
364
+ .filter((line) => !line.includes('@corva/ui'))
365
+ .join('\n');
366
+
367
+ console.log(error);
368
+ }
369
+
370
+ if (proc.status !== 0) {
371
+ console.error(`\`${command} ${args.join(' ')}\` failed`);
372
+
373
+ return;
374
+ }
375
+
376
+ logger.log(chalk.green('Successfull project install'));
377
+ }
378
+
379
+ async function helpCommands(manifest, { packageManager: displayedCommand }) {
380
+ if (!manifest.isUi()) {
381
+ return;
382
+ }
383
+
384
+ const useYarn = displayedCommand === 'yarn';
385
+
386
+ logger.log('Inside that directory, you can run several commands:');
387
+ logger.log();
388
+ logger.log(chalk.cyan(` ${displayedCommand} start`));
389
+ logger.log(' Starts the development server.');
390
+ logger.log();
391
+ logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`));
392
+ logger.log(' Bundles the app into static files for production.');
393
+ logger.log();
394
+ logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}zip`));
395
+ logger.log(' Bundles the app into ZIP file in app root directory');
396
+ logger.log();
397
+ logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}release`));
398
+ logger.log(' Uploads the app ZIP to Corva');
399
+ logger.log();
400
+ }
401
+
402
+ function startingMessage() {
403
+ clear();
404
+ console.log(chalk.green(' Welcome to apps generator for:'));
405
+ console.log(chalk.cyan(figlet.textSync('CORVA.AI', { horizontalLayout: 'full' })));
406
+ }
407
+
408
+ function checkOptions(opts) {
409
+ let isValid = true;
410
+ const values = {};
411
+
412
+ getManifestMandatoryKeys(opts).forEach((key) => {
413
+ if (!opts[key]) {
414
+ isValid = false;
415
+ }
416
+
417
+ values[key] = opts[key];
418
+ });
419
+
420
+ return {
421
+ isValid,
422
+ values,
423
+ };
424
+ }
@@ -0,0 +1,43 @@
1
+ import { Command, Option } from 'commander';
2
+ import { runFlow } from '../flow.js';
3
+ import { RELEASE_FLOW } from '../flows/release.js';
4
+ import { getRealWorkingDir } from '../helpers/commands.js';
5
+ import { apiKeyOption } from '../options/api-key.js';
6
+ import { bumpVersionOption } from '../options/bump-version.js';
7
+ import { envOption } from '../options/env.js';
8
+ import { originalCwdOption } from '../options/original-cwd.js';
9
+ import { silentOption } from '../options/silent.js';
10
+ import { ensureBumpVersion } from '../helpers/cli-version.js';
11
+
12
+ export const releaseCommand = new Command('release')
13
+ .description('Release app')
14
+ .argument('<project-directory>', 'Project directory to work with')
15
+ .argument('[patterns...]', 'Additional patterns to zip', [])
16
+ .addOption(bumpVersionOption)
17
+ .addOption(new Option('--ignored-files [string...]', 'Patterns to skip zip').default([]))
18
+ .addOption(silentOption)
19
+ .addOption(envOption)
20
+ .addOption(apiKeyOption)
21
+ .addOption(originalCwdOption)
22
+ .addOption(new Option('--notes [string]', 'Add custom notes to published app'))
23
+ .addOption(new Option('--label [string]', 'Put a label on the release').choices(['BETA', 'PROD']))
24
+ .addOption(new Option('--remove-on-fail [boolean]', 'Remove release if it fails during deployment').default(false))
25
+ .addOption(
26
+ new Option('--remove-on-success [boolean]', 'App package (.zip) will not be deleted after upload').default(true),
27
+ )
28
+ .addOption(
29
+ new Option(
30
+ '--remove-existing [boolean]',
31
+ 'If package version is already taken - remove the previously published package and upload a new one',
32
+ ).default(false),
33
+ )
34
+ // .addOption(new Option('--zip-file-name [string]', 'Prebuilt zip file name in dir'))
35
+ .action(async (dirName, patterns, options) => {
36
+ options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
37
+
38
+ await runFlow(RELEASE_FLOW, {
39
+ dirName: getRealWorkingDir(dirName, options),
40
+ patterns,
41
+ options,
42
+ });
43
+ });
@@ -0,0 +1,25 @@
1
+ import { Command, Option } from 'commander';
2
+
3
+ import { runFlow } from '../flow.js';
4
+ import { RERUN_FLOW } from '../flows/rerun.js';
5
+ import { getRealWorkingDir } from '../helpers/commands.js';
6
+ import { apiKeyOption } from '../options/api-key.js';
7
+ import { appVersion } from '../options/app-version.js';
8
+ import { envOption } from '../options/env.js';
9
+ import { originalCwdOption } from '../options/original-cwd.js';
10
+ import { silentOption } from '../options/silent.js';
11
+
12
+ export const rerunCommand = new Command('rerun')
13
+ .description('Rerun app')
14
+ .argument('<project-directory>', 'Project directory to work with')
15
+ .addOption(apiKeyOption)
16
+ .addOption(envOption)
17
+ .addOption(silentOption)
18
+ .addOption(appVersion)
19
+ .addOption(new Option('--assets [assets...]', 'Assets IDs list', []).conflicts('companyId'))
20
+ .addOption(new Option('--company-id [number]', 'Company ID', []))
21
+ .addOption(new Option('--interval [number]', 'Interval for scheduler apps (exp. 1200)'))
22
+ .addOption(originalCwdOption)
23
+ .action(async (dirName, options) => {
24
+ await runFlow(RERUN_FLOW, { dirName: getRealWorkingDir(dirName, options), options });
25
+ });
@@ -0,0 +1,32 @@
1
+ import { Command, Option } from 'commander';
2
+ import _ from 'lodash/fp.js';
3
+
4
+ import { runFlow } from '../flow.js';
5
+ import { ZIP_FLOW } from '../flows/zip.js';
6
+ import { getRealWorkingDir, silencer } from '../helpers/commands.js';
7
+ import { bumpVersionOption } from '../options/bump-version.js';
8
+ import { originalCwdOption } from '../options/original-cwd.js';
9
+ import { silentOption } from '../options/silent.js';
10
+ import { ensureBumpVersion } from '../helpers/cli-version.js';
11
+
12
+ export const zipCommand = new Command('zip')
13
+ .description('Bundle app')
14
+ .argument('<project-directory>', 'Project directory to work with')
15
+ .argument('[patterns...]', 'Additional patterns to zip', [])
16
+ .addOption(bumpVersionOption)
17
+ .addOption(new Option('--ignored-files [ignoredFiles...]', 'Patterns to skip zip', []))
18
+ .addOption(originalCwdOption)
19
+ .addOption(silentOption)
20
+ .action(
21
+ silencer(async (dirName, patterns, options) => {
22
+ options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
23
+
24
+ console.log(getRealWorkingDir(dirName, options), options);
25
+
26
+ return runFlow(ZIP_FLOW, {
27
+ dirName: getRealWorkingDir(dirName, options),
28
+ patterns,
29
+ options,
30
+ }).then(_.get('zipFileName'));
31
+ }),
32
+ );
@@ -3,6 +3,7 @@ export const APP_RUNTIMES = {
3
3
  // NODE12: 'nodejs12.x',
4
4
  // NODE14: 'nodejs14.x',
5
5
  NODE16: 'nodejs16.x',
6
+ NODE18: 'nodejs18.x',
6
7
  PYTHON3_8: 'python3.8',
7
8
  PYTHON3_9: 'python3.9',
8
9
  };
@@ -11,7 +11,7 @@ const SCHEDULER_MAPPING = [SCHEDULER_TYPE_DATA_TIME, SCHEDULER_TYPE_DEPTH, SCHED
11
11
  {},
12
12
  );
13
13
 
14
- const NODE_RUNTIMES = [APP_RUNTIMES.NODE12, APP_RUNTIMES.NODE14, APP_RUNTIMES.NODE16];
14
+ const NODE_RUNTIMES = [APP_RUNTIMES.NODE16, APP_RUNTIMES.NODE18];
15
15
 
16
16
  export class Manifest {
17
17
  constructor(manifest) {
@@ -5,7 +5,7 @@ import _ from 'lodash/fp.js';
5
5
  import { promises as fs } from 'node:fs';
6
6
  import { resolve } from 'node:path';
7
7
  import { promisify } from 'node:util';
8
- import { getIncreasedVersion } from '../../scripts/utils/version.js';
8
+ import { getIncreasedVersion } from '../../helpers/cli-version.js';
9
9
  import { loadJson } from '../lib/json.js';
10
10
  import { StepError } from '../lib/step-error.js';
11
11
 
@@ -5,7 +5,7 @@ import inquirer from 'inquirer';
5
5
  import { join } from 'path';
6
6
  import * as url from 'url';
7
7
 
8
- import { logger } from '../../helpers/logger.js';
8
+ import { logger } from './logger.js';
9
9
  import fs from 'fs-extra';
10
10
 
11
11
  const npm = new NpmApi();
@@ -16,7 +16,7 @@ const code = chalk.cyan;
16
16
  const asterisks = '****************************************************************';
17
17
 
18
18
  const getCurrentVersion = async () =>
19
- (await fs.readJSON(join(url.fileURLToPath(new URL('.', import.meta.url)), '../../../package.json'))).version;
19
+ (await fs.readJSON(join(url.fileURLToPath(new URL('.', import.meta.url)), '../../package.json'))).version;
20
20
  const getLatestVersion = async () => npm.repo('@corva/create-app').prop('version');
21
21
 
22
22
  // NOTE: Stop process and show error if version is outdated
@@ -0,0 +1,13 @@
1
+ import { resolve } from 'node:path';
2
+
3
+ export const silencer =
4
+ (handler) =>
5
+ async (...args) => {
6
+ const result = await handler(...args);
7
+
8
+ if (args[args.length - 2].silent && result) {
9
+ console.log(result);
10
+ }
11
+ };
12
+
13
+ export const getRealWorkingDir = (relativePath, options) => resolve(options.originalCwd, relativePath);
@@ -6,6 +6,25 @@ import { logger } from './logger.js';
6
6
 
7
7
  const debug = debugFn('cca:versioning');
8
8
 
9
+ /**
10
+ *
11
+ * @param {string} root
12
+ */
13
+ export async function initVersioning(root) {
14
+ logger.log();
15
+
16
+ if (!tryGitInit(root)) {
17
+ logger.log('Already in a git repository. Skipping git initialization.');
18
+
19
+ return;
20
+ }
21
+
22
+ if (tryGitCommit(root)) {
23
+ logger.log();
24
+ logger.log('Created git commit');
25
+ }
26
+ }
27
+
9
28
  export function isInGitRepository(appPath) {
10
29
  try {
11
30
  execSync('git rev-parse --is-inside-work-tree', {
@@ -73,15 +92,3 @@ export function tryGitCommit(appPath) {
73
92
  return false;
74
93
  }
75
94
  }
76
-
77
- export function shouldUseYarn(appPath) {
78
- try {
79
- execSync('yarnpkg --version', { stdio: 'ignore', cwd: appPath });
80
-
81
- return true;
82
- } catch (e) {
83
- debug(e);
84
-
85
- return false;
86
- }
87
- }
package/lib/main.js CHANGED
@@ -1,71 +1,17 @@
1
- /* eslint-disable no-undef */
2
1
  import chalk from 'chalk';
3
- import { Command, CommanderError, Option } from 'commander';
4
- import figlet from 'figlet';
5
- import fs from 'fs-extra';
6
- import inquirer from 'inquirer';
7
- import os from 'node:os';
8
- import path, { resolve } from 'node:path';
2
+ import { Command, CommanderError } from 'commander';
9
3
  import semver from 'semver';
10
4
 
11
- import * as manifestHelpers from './helpers/manifest.js';
12
- import * as utils from './helpers/utils.js';
13
- import * as versioning from './helpers/versioning.js';
14
- import { ensureBumpVersion, ensureLatestVersion, warnIfOutdated } from './scripts/utils/version.js';
15
-
16
- import * as manifestConstants from './constants/manifest.js';
17
- import { getDefaultsForPackageJson } from './constants/package.js';
18
-
19
- import spawn from 'cross-spawn';
20
- import _ from 'lodash/fp.js';
21
- import { clear } from 'node:console';
22
- import { existsSync } from 'node:fs';
23
- import { fileURLToPath } from 'node:url';
24
- import packageJson from '../package.json' assert { type: 'json' };
25
- import {
26
- apiKeyOption,
27
- appVersion,
28
- bumpVersionOption,
29
- envOption,
30
- originalCwdOption,
31
- silentOption,
32
- } from './bump-version.option.js';
5
+ import { warnIfOutdated } from './helpers/cli-version.js';
33
6
  import { ERROR_ICON } from './constants/messages.js';
34
- import { runFlow } from './flow.js';
35
- import { ATTACH_FLOW } from './flows/attach.js';
36
- import { Manifest } from './flows/lib/manifest.js';
37
7
  import { StepError } from './flows/lib/step-error.js';
38
- import { RELEASE_FLOW } from './flows/release.js';
39
- import { RERUN_FLOW } from './flows/rerun.js';
40
- import { ZIP_FLOW } from './flows/zip.js';
41
8
  import { logger } from './helpers/logger.js';
42
- import { IS_WINDOWS, resolveAppRuntime } from './helpers/resolve-app-runtime.js';
43
-
44
- const __filename = fileURLToPath(import.meta.url);
45
- const __dirname = path.dirname(__filename);
46
-
47
- const writejsonOptions = {
48
- spaces: 2,
49
- EOL: os.EOL,
50
- };
51
9
 
52
- const silencer =
53
- (handler) =>
54
- async (...args) => {
55
- const result = await handler(...args);
56
-
57
- if (args[args.length - 2].silent && result) {
58
- console.log(result);
59
- }
60
- };
61
-
62
- const getRealWorkingDir = (relativePath, options) => resolve(options.originalCwd, relativePath);
63
-
64
- function startingMessage() {
65
- clear();
66
- console.log(chalk.green(' Welcome to apps generator for:'));
67
- console.log(chalk.cyan(figlet.textSync('CORVA.AI', { horizontalLayout: 'full' })));
68
- }
10
+ import { zipCommand } from './commands/zip.js';
11
+ import { releaseCommand } from './commands/release.js';
12
+ import { rerunCommand } from './commands/rerun.js';
13
+ import { attachCommand } from './commands/attach.js';
14
+ import { createCommand } from './commands/create.js';
69
15
 
70
16
  function checkNodeVersion() {
71
17
  logger.write('Checking node version...');
@@ -87,30 +33,6 @@ function checkNodeVersion() {
87
33
  logger.write(' ✅ \n');
88
34
  }
89
35
 
90
- function checkOptions(opts) {
91
- let isValid = true;
92
- const values = {};
93
-
94
- manifestConstants.getManifestMandatoryKeys(opts).forEach((key) => {
95
- if (!opts[key]) {
96
- isValid = false;
97
- }
98
-
99
- values[key] = opts[key];
100
- });
101
-
102
- return {
103
- isValid,
104
- values,
105
- };
106
- }
107
-
108
- // eslint-disable-next-line no-unused-vars
109
- const printDeprecationNotice = (param) =>
110
- console.warn(
111
- chalk.bgYellowBright`DEPRECATED OPTION: ${param}` + ` Use ${chalk.cyan(`create-corva-app ${param} .`)} instead`,
112
- );
113
-
114
36
  export async function run() {
115
37
  const program = new Command('create-corva-app')
116
38
  .hook('preAction', async () => {
@@ -119,140 +41,12 @@ export async function run() {
119
41
  await warnIfOutdated();
120
42
  })
121
43
  .configureOutput({ writeErr: () => undefined })
122
- .exitOverride();
123
-
124
- const createCommand = program
125
- .command('create', { isDefault: true })
126
- .description('Create a new app')
127
- .argument('[project-directory]', 'project directory to work with', process.argv[process.argv.length - 1])
128
- .addOption(originalCwdOption)
129
- .usage(`${chalk.green('<project-directory>')} [options]`);
130
-
131
- manifestConstants.manifestOptions().forEach((value) => {
132
- const type = typeof value.default;
133
- const cliType = type === 'undefined' ? (value.choices ? ' [string]' : '') : ` [${type}]`;
134
- const alias = value.alias ? `-${value.alias}, ` : '';
135
- const optionString = `${alias}--${value.name}${cliType}`;
136
-
137
- const option = new Option(optionString, value.message);
138
-
139
- if (value.choices) {
140
- if (typeof value.choices === 'function') {
141
- option.choices(value.choices());
142
- } else {
143
- option.choices(value.choices.map((choice) => `${typeof choice === 'object' ? choice.value : choice}`));
144
- }
145
- }
146
-
147
- if (type === 'number') {
148
- option.argParser(Number);
149
- }
150
-
151
- if (type !== 'undefined') {
152
- option.default(value.default);
153
- }
154
-
155
- createCommand.addOption(option);
156
- });
157
-
158
- createCommand.version(packageJson.version);
159
-
160
- createCommand.action(async (dirName, options) => {
161
- if (options.zip || options.release) {
162
- options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
163
- }
164
-
165
- startingMessage();
166
-
167
- // NOTE: Default action
168
- await createApp(dirName, options);
169
- });
170
-
171
- program
172
- .command('zip')
173
- .description('Bundle app')
174
- .argument('<project-directory>', 'Project directory to work with')
175
- .argument('[patterns...]', 'Additional patterns to zip', [])
176
- .addOption(bumpVersionOption)
177
- .addOption(new Option('--ignored-files [ignoredFiles...]', 'Patterns to skip zip', []))
178
- .addOption(originalCwdOption)
179
- .addOption(silentOption)
180
- .action(
181
- silencer(async (dirName, patterns, options) => {
182
- options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
183
-
184
- console.log(getRealWorkingDir(dirName, options), options);
185
-
186
- return runFlow(ZIP_FLOW, {
187
- dirName: getRealWorkingDir(dirName, options),
188
- patterns,
189
- options,
190
- }).then(_.get('zipFileName'));
191
- }),
192
- );
193
-
194
- program
195
- .command('release')
196
- .description('Release app')
197
- .argument('<project-directory>', 'Project directory to work with')
198
- .argument('[patterns...]', 'Additional patterns to zip', [])
199
- .addOption(bumpVersionOption)
200
- .addOption(new Option('--ignored-files [string...]', 'Patterns to skip zip').default([]))
201
- .addOption(silentOption)
202
- .addOption(envOption)
203
- .addOption(apiKeyOption)
204
- .addOption(originalCwdOption)
205
- .addOption(new Option('--notes [string]', 'Add custom notes to published app'))
206
- .addOption(new Option('--label [string]', 'Put a label on the release').choices(['BETA', 'PROD']))
207
- .addOption(new Option('--remove-on-fail [boolean]', 'Remove release if it fails during deployment').default(false))
208
- .addOption(
209
- new Option('--remove-on-success [boolean]', 'App package (.zip) will not be deleted after upload').default(true),
210
- )
211
- .addOption(
212
- new Option(
213
- '--remove-existing [boolean]',
214
- 'If package version is already taken - remove the previously published package and upload a new one',
215
- ).default(false),
216
- )
217
- // .addOption(new Option('--zip-file-name [string]', 'Prebuilt zip file name in dir'))
218
- .action(async (dirName, patterns, options) => {
219
- options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
220
-
221
- await runFlow(RELEASE_FLOW, {
222
- dirName: getRealWorkingDir(dirName, options),
223
- patterns,
224
- options,
225
- });
226
- });
227
-
228
- program
229
- .command('rerun')
230
- .description('Rerun app')
231
- .argument('<project-directory>', 'Project directory to work with')
232
- .addOption(apiKeyOption)
233
- .addOption(envOption)
234
- .addOption(silentOption)
235
- .addOption(appVersion)
236
- .addOption(new Option('--assets [assets...]', 'Assets IDs list', []).conflicts('companyId'))
237
- .addOption(new Option('--company-id [number]', 'Company ID', []))
238
- .addOption(new Option('--interval [number]', 'Interval for scheduler apps (exp. 1200)'))
239
- .addOption(originalCwdOption)
240
- .action(async (dirName, options) => {
241
- await runFlow(RERUN_FLOW, { dirName: getRealWorkingDir(dirName, options), options });
242
- });
243
-
244
- program
245
- .command('attach')
246
- .description('Add app to live assets streams')
247
- .argument('<project-directory>', 'Project directory to work with')
248
- .addOption(apiKeyOption)
249
- .addOption(envOption)
250
- .addOption(silentOption)
251
- .addOption(appVersion)
252
- .addOption(originalCwdOption)
253
- .action(async (dirName, options) => {
254
- await runFlow(ATTACH_FLOW, { dirName: getRealWorkingDir(dirName, options), options });
255
- });
44
+ .exitOverride()
45
+ .addCommand(createCommand, { isDefault: true })
46
+ .addCommand(zipCommand)
47
+ .addCommand(releaseCommand)
48
+ .addCommand(rerunCommand)
49
+ .addCommand(attachCommand);
256
50
 
257
51
  try {
258
52
  await program.parseAsync(process.argv);
@@ -313,339 +107,3 @@ const handleCommanderError = (program, e) => {
313
107
  }
314
108
  }
315
109
  };
316
-
317
- /**
318
- *
319
- * @param {import('./flows/lib/manifest').Manifest} manifest
320
- */
321
- const getEnvManagementLink = (manifest) => {
322
- if (manifest.isJs()) {
323
- if (IS_WINDOWS) {
324
- return 'https://github.com/coreybutler/nvm-windows';
325
- }
326
-
327
- return 'https://github.com/nvm-sh/nvm';
328
- }
329
-
330
- if (IS_WINDOWS) {
331
- return 'https://github.com/pyenv-win/pyenv-win';
332
- }
333
-
334
- return 'https://github.com/pyenv/pyenv';
335
- };
336
-
337
- async function initPackage(projectName, opts) {
338
- const manifest = new Manifest(manifestHelpers.fillManifest(opts));
339
- const runtime = resolveAppRuntime(opts);
340
-
341
- if (!(await runtime.isRuntimeAvailable())) {
342
- throw new Error(
343
- `Runtime "${opts.runtime}" is not available locally. Please proceed to ${chalk.green(
344
- getEnvManagementLink(manifest),
345
- )} to install it locally.`,
346
- );
347
- }
348
-
349
- if (manifest.isUi()) {
350
- await ensureLatestVersion();
351
- }
352
-
353
- const root = getRealWorkingDir(projectName, opts);
354
-
355
- logger.log(`Creating a new Corva app in ${chalk.green(root)}.`);
356
-
357
- await fs.ensureDir(root);
358
-
359
- if ((await fs.readdir(root)).length) {
360
- const shouldCleanup = await inquirer
361
- .prompt([
362
- {
363
- message: `Directory "${root}" is not empty. Clean it to proceed?`,
364
- name: 'cleanup',
365
- type: 'confirm',
366
- },
367
- ])
368
- .then(_.get('cleanup'));
369
-
370
- if (shouldCleanup) {
371
- await fs.emptyDir(root);
372
- } else {
373
- throw new Error(`Directory is not empty: ${root}`);
374
- }
375
- }
376
-
377
- await fs.writeJSON(path.join(root, 'manifest.json'), manifest.manifest, writejsonOptions);
378
-
379
- await addTemplate(root, manifest, runtime);
380
- await configureApp(root, manifest, runtime);
381
-
382
- opts.dependenciesInstall && (await installDependencies(root, manifest, runtime));
383
-
384
- opts.gitInit && (await initVersioning(root, manifest, runtime));
385
-
386
- logger.log();
387
- logger.log(`Success! Created ${chalk.green(manifest.name)} at ${chalk.yellow(root)}`);
388
-
389
- helpCommands(manifest, runtime);
390
-
391
- logger.log();
392
- }
393
-
394
- async function createApp(dirName, opts) {
395
- const { isValid, values } = checkOptions(opts);
396
-
397
- if (isValid) {
398
- Object.keys(values).forEach((key) => {
399
- logger.log(`${key} : ${values[key]}`);
400
- });
401
-
402
- return initPackage(dirName, opts);
403
- }
404
-
405
- console.log('Please fill your app Metadata');
406
-
407
- const answers = await inquirer.prompt(manifestConstants.manifestOptions(dirName), opts);
408
-
409
- return initPackage(dirName, answers);
410
- }
411
-
412
- /**
413
- *
414
- * @param {string} root
415
- * @param {import('./flows/lib/manifest').Manifest} manifest
416
- * @param {*} runtime
417
- */
418
- async function addTemplate(root, manifest, runtime) {
419
- logger.log(chalk.green('Copying app template...'));
420
- logger.log();
421
-
422
- const templateFolder = path.resolve(__dirname, '..', 'templates', manifest.templateName, runtime.language);
423
-
424
- utils.copyFolderRecursiveSync(templateFolder, root);
425
-
426
- if (manifest.isNode()) {
427
- utils.copyFolderRecursiveSync(path.resolve(__dirname, '..', 'common', 'node'), root);
428
- }
429
-
430
- if (manifest.isPython()) {
431
- utils.copyFolderRecursiveSync(path.resolve(__dirname, '..', 'common', 'python'), root);
432
- }
433
-
434
- if (!manifest.isUi()) {
435
- await utils.putVariablesInEnvFile(root, manifest);
436
- }
437
-
438
- // We can't have .gitignore file in our templates.
439
- // It's missing when @corva/create-app is installed.
440
- // That's why we manually rename gitignore to .gitignore after copying template
441
- const targetGitignore = path.join(root, '.gitignore');
442
-
443
- fs.renameSync(path.join(root, 'gitignore'), targetGitignore);
444
-
445
- if (runtime.language === 'typescript' && manifest.isNode()) {
446
- await fs.appendFile(targetGitignore, '\n**/*.js\n');
447
- }
448
-
449
- logger.log(chalk.green('Done: copying app template!'));
450
- }
451
-
452
- /**
453
- *
454
- * @param {string} root
455
- * @param {import('./flows/lib/manifest').Manifest} manifest
456
- * @param {*} runtime
457
- */
458
- async function configureApp(root, manifest, runtime) {
459
- if (manifest.isJs()) {
460
- await addNvmRc(root, manifest, runtime);
461
- await addPackageJSON(root, manifest, runtime);
462
- }
463
-
464
- if (manifest.isNode()) {
465
- await addTsConfigs(root, manifest, runtime);
466
- }
467
-
468
- if (manifest.isPython()) {
469
- await addPythonConfigs(root, manifest, runtime);
470
- }
471
- }
472
-
473
- const addNvmRc = async (root, manifest, runtime) => {
474
- await fs.outputFile(path.join(root, '.nvmrc'), `${runtime.semver}\n`);
475
- };
476
-
477
- /**
478
- *
479
- * @param {string} root
480
- * @param {Manifest} manifest
481
- * @param {import('./helpers/resolve-app-runtime.js').Runtime} runtime
482
- */
483
- const addPythonConfigs = async (root, manifest, runtime) => {
484
- await fs.writeFile(path.resolve(root, '.python-version'), `${runtime.semver}\n`);
485
- await fs.writeFile(path.resolve(root, '.python-virtualenv'), `${manifest.unix_name}\n`);
486
- };
487
-
488
- const addTsConfigs = (root, manifest, runtime) => {
489
- if (runtime.language !== 'typescript') {
490
- return;
491
- }
492
-
493
- return Promise.all([
494
- fs.writeJson(
495
- path.resolve(root, 'tsconfig.json'),
496
- {
497
- extends: `@tsconfig/node${runtime.version}/tsconfig.json`,
498
- compilerOptions: {
499
- inlineSourceMap: true,
500
- strict: false,
501
- },
502
- },
503
- writejsonOptions,
504
- ),
505
- fs.writeJson(
506
- path.resolve(root, 'tsconfig.build.json'),
507
- {
508
- extends: './tsconfig.json',
509
- include: ['lib/**/*.ts', 'index.ts'],
510
- exclude: ['node_modules', '**/*.spec.ts'],
511
- },
512
- writejsonOptions,
513
- ),
514
- ]);
515
- };
516
-
517
- /**
518
- *
519
- * @param {string} root
520
- * @param {import('./flows/lib/manifest').Manifest} manifest
521
- */
522
- function addPackageJSON(root, manifest, runtime) {
523
- const {
524
- version,
525
- description,
526
- scripts,
527
- dependencies,
528
- devDependencies,
529
- main,
530
- license = 'UNLICENSED',
531
- private: isPrivate = true,
532
- ...rest
533
- } = getDefaultsForPackageJson(manifest, runtime);
534
-
535
- const packageJson = {
536
- name: manifest.unix_name,
537
- version,
538
- description: manifest.description || description,
539
- main,
540
- private: isPrivate,
541
- license,
542
- engines: {
543
- node: `^${runtime.version}`,
544
- [runtime.packageManager]: '*',
545
- },
546
- scripts,
547
- dependencies,
548
- devDependencies,
549
- ...rest,
550
- };
551
-
552
- return fs.writeJSON(path.join(root, 'package.json'), packageJson, writejsonOptions);
553
- }
554
-
555
- /**
556
- * @param {string} root
557
- * @param {import('./flows/lib/manifest').Manifest} manifest
558
- * @param {import('./helpers/resolve-app-runtime.js').Runtime} runtime
559
- * @returns {Promise<void>}
560
- * @throws {Error}
561
- * @throws {import('child_process').ExecException}
562
- * @throws {import('child_process').SpawnSyncReturns<Buffer>}
563
- */
564
- async function installDependencies(root, manifest, runtime) {
565
- const command = manifest.isJs() ? runtime.packageManager : 'make';
566
-
567
- if (IS_WINDOWS && !manifest.isJs()) {
568
- logger.log();
569
- logger.log(`⚠️ ${chalk.yellow('Please install project dependencies manually')}`);
570
-
571
- return;
572
- }
573
-
574
- const args = ['install'];
575
- const opts = { stdio: ['inherit', 'inherit', 'pipe'], cwd: root };
576
-
577
- if (process.env.CI && command === 'yarn') {
578
- args.push('--cache-folder=".yarn-cache"');
579
- }
580
-
581
- logger.log(chalk.yellow(`Installing template dependencies using ${runtime.packageManager}...`));
582
-
583
- const proc =
584
- manifest.isJs() && existsSync(`${os.homedir()}/.nvm/nvm.sh`)
585
- ? spawn.sync(`\\. ${os.homedir()}/.nvm/nvm.sh && nvm i && ${command} ${args.join(' ')}`, {
586
- shell: true,
587
- ...opts,
588
- })
589
- : spawn.sync(command, args, opts);
590
-
591
- if (proc.stderr) {
592
- const error = proc.stderr
593
- .toString('utf8')
594
- .split('\n')
595
- // NOTE: filter out warnings caused by @corva/ui peer dependencies
596
- .filter((line) => !line.includes('@corva/ui'))
597
- .join('\n');
598
-
599
- console.log(error);
600
- }
601
-
602
- if (proc.status !== 0) {
603
- console.error(`\`${command} ${args.join(' ')}\` failed`);
604
-
605
- return;
606
- }
607
-
608
- logger.log(chalk.green('Successfull project install'));
609
- }
610
-
611
- /**
612
- *
613
- * @param {string} root
614
- */
615
- async function initVersioning(root) {
616
- logger.log();
617
-
618
- if (!versioning.tryGitInit(root)) {
619
- logger.log('Already in a git repository. Skipping git initialization.');
620
-
621
- return;
622
- }
623
-
624
- if (versioning.tryGitCommit(root)) {
625
- logger.log();
626
- logger.log('Created git commit');
627
- }
628
- }
629
-
630
- async function helpCommands(manifest, { packageManager: displayedCommand }) {
631
- if (!manifest.isUi()) {
632
- return;
633
- }
634
-
635
- const useYarn = displayedCommand === 'yarn';
636
-
637
- logger.log('Inside that directory, you can run several commands:');
638
- logger.log();
639
- logger.log(chalk.cyan(` ${displayedCommand} start`));
640
- logger.log(' Starts the development server.');
641
- logger.log();
642
- logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}build`));
643
- logger.log(' Bundles the app into static files for production.');
644
- logger.log();
645
- logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}zip`));
646
- logger.log(' Bundles the app into ZIP file in app root directory');
647
- logger.log();
648
- logger.log(chalk.cyan(` ${displayedCommand} ${useYarn ? '' : 'run '}release`));
649
- logger.log(' Uploads the app ZIP to Corva');
650
- logger.log();
651
- }
@@ -0,0 +1,6 @@
1
+ import { Option } from 'commander';
2
+
3
+ export const apiKeyOption = new Option(
4
+ '--api-key [string]',
5
+ 'Pre generated API key for authorization during app upload',
6
+ );
@@ -0,0 +1,3 @@
1
+ import { Option } from 'commander';
2
+
3
+ export const appVersion = new Option('--app-version [number]', 'App version (exp. 1, 2, 3)');
@@ -0,0 +1,19 @@
1
+ import { InvalidArgumentError, Option } from 'commander';
2
+ import semver from 'semver';
3
+
4
+ const flags = '--bump-version <string>';
5
+ const description = 'Bump version';
6
+ const choices = ['major', 'minor', 'patch', 'skip'];
7
+
8
+ function argParser(value, previous) {
9
+ // eslint-disable-next-line no-invalid-this
10
+ if (this.argChoices.includes(value) || semver.valid(value)) {
11
+ return value;
12
+ }
13
+
14
+ throw new InvalidArgumentError(
15
+ // eslint-disable-next-line no-invalid-this
16
+ `Allowed choices are ${this.argChoices.map((choice) => `"${choice}"`).join(', ')} or a valid semver version.`,
17
+ );
18
+ }
19
+ export const bumpVersionOption = new Option(flags, description).choices(choices).argParser(argParser);
@@ -0,0 +1,3 @@
1
+ import { Option } from 'commander';
2
+
3
+ export const envOption = new Option('--env [string]', 'Environment to use').choices(['qa', 'staging', 'production']);
@@ -0,0 +1,3 @@
1
+ import { Option } from 'commander';
2
+
3
+ export const originalCwdOption = new Option('--original-cwd <string>').hideHelp();
@@ -0,0 +1,3 @@
1
+ import { Option } from 'commander';
2
+
3
+ export const silentOption = new Option('--silent [boolean]', 'Only log result of the operation').default(false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corva/create-app",
3
- "version": "0.49.0-0",
3
+ "version": "0.49.0-2",
4
4
  "private": false,
5
5
  "description": "Create an app to use it in CORVA.AI",
6
6
  "keywords": [
@@ -1,40 +0,0 @@
1
- import chalk from 'chalk';
2
- import { InvalidArgumentError, Option } from 'commander';
3
- import semver from 'semver';
4
-
5
- const flags = '--bump-version <string>';
6
- const description = 'Bump version';
7
- const choices = ['major', 'minor', 'patch', 'skip'];
8
-
9
- function argParser(value, previous) {
10
- // eslint-disable-next-line no-invalid-this
11
- if (this.argChoices.includes(value) || semver.valid(value)) {
12
- return value;
13
- }
14
-
15
- throw new InvalidArgumentError(
16
- // eslint-disable-next-line no-invalid-this
17
- `Allowed choices are ${this.argChoices.map((choice) => `"${choice}"`).join(', ')} or a valid semver version.`,
18
- );
19
- }
20
- export const bumpVersionOption = new Option(flags, description).choices(choices).argParser(argParser);
21
-
22
- export const apiKeyOption = new Option(
23
- '--api-key [string]',
24
- 'Pre generated API key for authorization during app upload',
25
- );
26
-
27
- export const appVersion = new Option('--app-version [number]', 'App version (exp. 1, 2, 3)');
28
-
29
- export const envOption = new Option('--env [string]', 'Environment to use').choices(['qa', 'staging', 'production']);
30
-
31
- export const silentOption = new Option('--silent [boolean]', 'Only log result of the operation').default(false);
32
-
33
- export const originalCwdOption = new Option('--original-cwd <string>').hideHelp();
34
-
35
- export const bumpVersionOptionDeprecated = new Option(
36
- flags,
37
- chalk.bgYellow`DEPRECATED` + ` Use with ${chalk.cyan`zip`} or ${chalk.cyan`release`} command instead`,
38
- )
39
- .choices(choices)
40
- .argParser(argParser);