@ones-open/cli 2.1.0 → 2.1.1
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.
- package/bin/index.es.js +261 -0
- package/package.json +4 -4
package/bin/index.es.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { ONESProjectTemplate, getCliVersionByMetaPath, Version, tryGitInit, renameHiddenTemplateFiles, getNpm, getPackageInNodeModulesDir } from '@ones-open/cli-utils';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command, Option } from 'commander';
|
|
5
|
+
import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
|
|
6
|
+
import { checkIsLegalPluginType, getPluginProjectCreatingTasks } from '@ones-open/cli-plugin';
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
import { pathExists, copy } from 'fs-extra';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import Listr from 'listr';
|
|
11
|
+
import { isAbsolute, join, basename, dirname } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import envinfo from 'envinfo';
|
|
14
|
+
import { cwd } from 'process';
|
|
15
|
+
|
|
16
|
+
/* eslint-disable no-console */
|
|
17
|
+
const defaultConfig = {
|
|
18
|
+
System: ['OS', 'CPU', 'Memory', 'Shell'],
|
|
19
|
+
Binaries: ['Node', 'npm'],
|
|
20
|
+
npmPackages: ['@ones-open/cli-utils', '@ones-open/cli-plugin', '@ones-open/cli-monorepo'],
|
|
21
|
+
npmGlobalPackages: ['@ones-open/cli']
|
|
22
|
+
};
|
|
23
|
+
const defaultOptions = {
|
|
24
|
+
duplicates: true,
|
|
25
|
+
showNotFound: true
|
|
26
|
+
};
|
|
27
|
+
async function printEnvironmentInfo(config = defaultConfig, options = defaultOptions) {
|
|
28
|
+
const info = await envinfo.run(config, options);
|
|
29
|
+
console.log(chalk.bold('\nEnvironment Info:'), info);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const LEGAL_PROJECT_TYPE = Object.values(ONESProjectTemplate);
|
|
33
|
+
const LEGAL_PROJECT_TYPE_SET = new Set(LEGAL_PROJECT_TYPE);
|
|
34
|
+
const LEGAL_POLICY = ['simple', 'standard'];
|
|
35
|
+
function isLegalProjectType(projectType) {
|
|
36
|
+
return LEGAL_PROJECT_TYPE_SET.has(projectType);
|
|
37
|
+
}
|
|
38
|
+
function isLegalPolicy(policy) {
|
|
39
|
+
return _includesInstanceProperty(LEGAL_POLICY).call(LEGAL_POLICY, policy);
|
|
40
|
+
}
|
|
41
|
+
async function getRootPath(currentWorkingDirectory, specificPath) {
|
|
42
|
+
const hasSpecificPath = specificPath && specificPath.length > 0;
|
|
43
|
+
if (hasSpecificPath) {
|
|
44
|
+
// we had to check if the path is absolute or not
|
|
45
|
+
const isAbsolutePath = isAbsolute(specificPath);
|
|
46
|
+
const root = isAbsolutePath ? specificPath : join(currentWorkingDirectory, specificPath);
|
|
47
|
+
const isPathExists = await pathExists(root);
|
|
48
|
+
if (!isPathExists) {
|
|
49
|
+
throw new Error('The specific path does not exist on the file system');
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
hasSpecificPath,
|
|
53
|
+
root,
|
|
54
|
+
projectName: basename(root)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
hasSpecificPath,
|
|
59
|
+
root: currentWorkingDirectory,
|
|
60
|
+
projectName: basename(currentWorkingDirectory)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Copy the project basic template files
|
|
66
|
+
*
|
|
67
|
+
* We need to consider the path of current file path after complication.
|
|
68
|
+
* When we compute the path on the file system.
|
|
69
|
+
*
|
|
70
|
+
* e.g:
|
|
71
|
+
*
|
|
72
|
+
* Current file in `/Users/user/ones/cli/src/bin/index.ts`
|
|
73
|
+
* Then the location of current file after complication is `/Users/user/ones/cli/bin/index.js`
|
|
74
|
+
*/
|
|
75
|
+
async function copyBasicTemplateFiles(projectType, projectPath) {
|
|
76
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
77
|
+
const currentFileDir = dirname(currentFilePath);
|
|
78
|
+
const templatePath = join(currentFileDir, '../template');
|
|
79
|
+
if (projectType === ONESProjectTemplate.Monorepo) {
|
|
80
|
+
await copy(templatePath, projectPath);
|
|
81
|
+
await renameHiddenTemplateFiles(projectPath);
|
|
82
|
+
} else {
|
|
83
|
+
// Only copy the package.json for the plugin project creating
|
|
84
|
+
const basicTemplatePackageJsonPath = join(templatePath, 'package.json');
|
|
85
|
+
const packageJsonPath = join(projectPath, 'package.json');
|
|
86
|
+
await copy(basicTemplatePackageJsonPath, packageJsonPath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function installSubCli({
|
|
90
|
+
root,
|
|
91
|
+
subCliName,
|
|
92
|
+
installLocalDependencies,
|
|
93
|
+
distTag
|
|
94
|
+
}) {
|
|
95
|
+
const cliNameWithVersionSuffix = `${subCliName}@${distTag}`;
|
|
96
|
+
const installCommand = getNpm();
|
|
97
|
+
const installArgs = installLocalDependencies ? ['link', subCliName, '--save-dev', '--no-optional'] : ['install', cliNameWithVersionSuffix, '--save-dev', '--no-optional'];
|
|
98
|
+
await execa(installCommand, installArgs, {
|
|
99
|
+
cwd: root,
|
|
100
|
+
stdio: 'ignore'
|
|
101
|
+
});
|
|
102
|
+
const subCliPath = getPackageInNodeModulesDir(root, subCliName);
|
|
103
|
+
const subCliPackageJsonPath = join(subCliPath, 'package.json');
|
|
104
|
+
const isSubCliInstalled = await pathExists(subCliPackageJsonPath);
|
|
105
|
+
if (!isSubCliInstalled) {
|
|
106
|
+
throw new Error(`${subCliName} does not exist in node_modules`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* TODO: support different project types
|
|
112
|
+
*/
|
|
113
|
+
function getExternalTaskByTemplateType(currentWorkingDirectory, projectCreatingParams, options) {
|
|
114
|
+
const {
|
|
115
|
+
template
|
|
116
|
+
} = projectCreatingParams;
|
|
117
|
+
if (template === ONESProjectTemplate.Plugin) {
|
|
118
|
+
return getPluginProjectCreatingTasks({
|
|
119
|
+
currentWorkingDirectory,
|
|
120
|
+
projectCreatingParams,
|
|
121
|
+
options
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
async function createProject(rawProjectName, options) {
|
|
127
|
+
try {
|
|
128
|
+
const {
|
|
129
|
+
projectType,
|
|
130
|
+
specificPath,
|
|
131
|
+
useDefaultPreset,
|
|
132
|
+
installLocalDependencies,
|
|
133
|
+
distTag: rawDistTag,
|
|
134
|
+
pluginType,
|
|
135
|
+
policy
|
|
136
|
+
} = options;
|
|
137
|
+
const cliVersion = await getCliVersionByMetaPath(import.meta.url);
|
|
138
|
+
if (!cliVersion) throw new Error('Get sub cli version failed.');
|
|
139
|
+
const distTag = rawDistTag ? rawDistTag :
|
|
140
|
+
// Get ONES CLI major version to match correct dependencies version
|
|
141
|
+
new Version(cliVersion).major;
|
|
142
|
+
if (!projectType || !isLegalProjectType(projectType)) {
|
|
143
|
+
throw new Error(`Illegal project type: ${projectType}`);
|
|
144
|
+
}
|
|
145
|
+
if (!checkIsLegalPluginType(pluginType)) {
|
|
146
|
+
throw new Error(`Illegal plugin type: ${pluginType}`);
|
|
147
|
+
}
|
|
148
|
+
if (!isLegalPolicy(policy)) {
|
|
149
|
+
throw new Error(`Illegal policy: ${policy}`);
|
|
150
|
+
}
|
|
151
|
+
const {
|
|
152
|
+
root,
|
|
153
|
+
projectName
|
|
154
|
+
} = await getRootPath(cwd(), specificPath);
|
|
155
|
+
const defaultProjectName = rawProjectName || projectName;
|
|
156
|
+
let projectCreatingParams = {
|
|
157
|
+
template: ONESProjectTemplate.Plugin,
|
|
158
|
+
name: defaultProjectName,
|
|
159
|
+
description: '',
|
|
160
|
+
appID: ''
|
|
161
|
+
};
|
|
162
|
+
const prompts = [{
|
|
163
|
+
type: 'list',
|
|
164
|
+
name: 'template',
|
|
165
|
+
message: 'Choose a template:',
|
|
166
|
+
choices: LEGAL_PROJECT_TYPE,
|
|
167
|
+
default: projectCreatingParams.template,
|
|
168
|
+
// Temporary hide the monorepo template type until we support it
|
|
169
|
+
when: false
|
|
170
|
+
// when: !projectType || !templates.includes(projectType),
|
|
171
|
+
}, {
|
|
172
|
+
type: 'input',
|
|
173
|
+
name: 'appID',
|
|
174
|
+
message: 'Project app ID(Refer to https://developer.ones.com/docs/guide/developer-license to learn how to get the appID.):',
|
|
175
|
+
validate: rawInput => {
|
|
176
|
+
const input = rawInput.trim();
|
|
177
|
+
if (input.length === 0) return 'Project app ID is required and cannot be empty';
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}, {
|
|
181
|
+
type: 'input',
|
|
182
|
+
name: 'name',
|
|
183
|
+
message: 'Project name:',
|
|
184
|
+
default: defaultProjectName,
|
|
185
|
+
validate: rawInput => {
|
|
186
|
+
const input = rawInput.trim();
|
|
187
|
+
if (input.length === 0) return 'Project name is required and cannot be empty';
|
|
188
|
+
return true;
|
|
189
|
+
},
|
|
190
|
+
when: !useDefaultPreset
|
|
191
|
+
}, {
|
|
192
|
+
type: 'input',
|
|
193
|
+
name: 'description',
|
|
194
|
+
message: 'Project description:',
|
|
195
|
+
when: !useDefaultPreset
|
|
196
|
+
}];
|
|
197
|
+
|
|
198
|
+
// display interactive prompts
|
|
199
|
+
const answers = await inquirer.prompt(prompts);
|
|
200
|
+
Object.entries(answers).forEach(([key, value]) => {
|
|
201
|
+
if (!value) return;
|
|
202
|
+
projectCreatingParams = {
|
|
203
|
+
...projectCreatingParams,
|
|
204
|
+
[key]: value
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
const projectCreatingTasks = [{
|
|
208
|
+
title: 'Git init',
|
|
209
|
+
task: async (ctx, task) => {
|
|
210
|
+
try {
|
|
211
|
+
await tryGitInit(root);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (error instanceof Error) {
|
|
214
|
+
const {
|
|
215
|
+
message
|
|
216
|
+
} = error;
|
|
217
|
+
task.skip(message);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}, {
|
|
222
|
+
title: 'Copy basic template files',
|
|
223
|
+
task: () => copyBasicTemplateFiles(projectCreatingParams.template, root)
|
|
224
|
+
}, {
|
|
225
|
+
title: 'Install sub CLI dependencies',
|
|
226
|
+
task: () => {
|
|
227
|
+
const subCliName = `@ones-open/cli-${projectCreatingParams.template}`;
|
|
228
|
+
return installSubCli({
|
|
229
|
+
subCliName,
|
|
230
|
+
root,
|
|
231
|
+
installLocalDependencies,
|
|
232
|
+
distTag
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}];
|
|
236
|
+
const createProject = new Listr(projectCreatingTasks);
|
|
237
|
+
const externalTask = getExternalTaskByTemplateType(root, projectCreatingParams, {
|
|
238
|
+
...options,
|
|
239
|
+
distTag
|
|
240
|
+
});
|
|
241
|
+
externalTask && createProject.add(externalTask);
|
|
242
|
+
await createProject.run(projectCreatingParams);
|
|
243
|
+
console.log(chalk.bold('\nProject has been created'), `\n${chalk.bold('Project path:')} ${chalk.green(root)}`, `\n${chalk.bold('Project name:')} ${chalk.green(projectCreatingParams.name)}`, `\n${chalk.bold('Project type:')} ${chalk.green(projectCreatingParams.template)}`, `\n${chalk.bold('Project description:')} ${chalk.green(projectCreatingParams.description)}`, `\n${chalk.bold('Project sub CLI:')} ${chalk.green(`@ones-open/cli-${projectCreatingParams.template}`)}`);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error(chalk.red(error));
|
|
246
|
+
await printEnvironmentInfo();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const cliVersion = (await getCliVersionByMetaPath(import.meta.url)) || 'unknown';
|
|
251
|
+
const ones = new Command('ones');
|
|
252
|
+
const gray = chalk.gray;
|
|
253
|
+
ones.version(cliVersion, '-v, --version', 'output the current version');
|
|
254
|
+
ones.command('create [project-name]').description(`create project from preset project template by type
|
|
255
|
+
${gray(`
|
|
256
|
+
Tip: if you leave the [project-name] blank and
|
|
257
|
+
1. not specified the specific path, then will use current folder name as default project name
|
|
258
|
+
2. the specific path is also specified, then will use the folder name as default project name
|
|
259
|
+
`)}`).option('-d, --use-default-preset', 'skip prompts and use default preset').option('-s, --specific-path <path>', 'create at a specific path, it will automatically detect relative or absolute path').option('--plugin-type [type]', 'support type: team, organization', 'team').option('--policy <policy>', 'support policy: simple, standard', 'simple').addOption(new Option('-t, --project-type <type>', 'the type of project template, support: monorepo, plugin').default('plugin').hideHelp(true)).addOption(new Option('--install-local-dependencies', 'development only, install local dependencies after create project').hideHelp(true)).addOption(new Option('--dist-tag <tag>', 'specify the dist tag of sub CLI dependencies, default: latest').hideHelp(true)).addOption(new Option('--ones-version <onesVersion>', 'specify the version of ONES')).action(createProject);
|
|
260
|
+
ones.command('envinfo').description('print environment info').action(printEnvironmentInfo);
|
|
261
|
+
ones.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ones-open/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Command line interface for developers",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ones": "./bin/index.es.js"
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@ones-open/cli-plugin": "^2.1.
|
|
44
|
-
"@ones-open/cli-utils": "^2.1.
|
|
43
|
+
"@ones-open/cli-plugin": "^2.1.1",
|
|
44
|
+
"@ones-open/cli-utils": "^2.1.1",
|
|
45
45
|
"chalk": "~5.0.1",
|
|
46
46
|
"commander": "~9.4.0",
|
|
47
47
|
"envinfo": "~7.8.1",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"@types/listr": "^0.14.4"
|
|
57
57
|
},
|
|
58
58
|
"type": "module",
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "1e51d94a7a0362a4d26958a4f47b116914e12e5f"
|
|
60
60
|
}
|