@farris/cli 1.0.8 → 1.0.11
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/ci/cli.js +246 -20
- package/package.json +3 -2
package/ci/cli.js
CHANGED
@@ -4,7 +4,11 @@
|
|
4
4
|
|
5
5
|
const fs = require('fs');
|
6
6
|
const path = require('path');
|
7
|
+
const log = require("npmlog");
|
8
|
+
const moment = require("moment");
|
7
9
|
const childProcess = require("@lerna/child-process");
|
10
|
+
const { Project } = require("@lerna/project");
|
11
|
+
|
8
12
|
|
9
13
|
const yargs = require('yargs/yargs');
|
10
14
|
const cli = yargs(process.argv.slice(2), process.cwd())
|
@@ -17,8 +21,8 @@ cli
|
|
17
21
|
return yargs;
|
18
22
|
},
|
19
23
|
(argv) => {
|
20
|
-
const
|
21
|
-
checkProjectChanges(
|
24
|
+
const projectPath = argv.project;
|
25
|
+
checkProjectChanges(projectPath);
|
22
26
|
}
|
23
27
|
)
|
24
28
|
.command(
|
@@ -58,26 +62,67 @@ cli
|
|
58
62
|
});
|
59
63
|
}
|
60
64
|
)
|
65
|
+
.command(
|
66
|
+
'publishAll',
|
67
|
+
'Publish all packages that have changed sence latst publish.',
|
68
|
+
(yargs) => {
|
69
|
+
return yargs;
|
70
|
+
},
|
71
|
+
(argv) => {
|
72
|
+
const projectPath = argv.project;
|
73
|
+
const url = argv.url;
|
74
|
+
publishAll(url);
|
75
|
+
}
|
76
|
+
)
|
61
77
|
.argv;
|
62
78
|
|
79
|
+
/**
|
80
|
+
* @param {import("@lerna/child-process").ExecOpts} execOpts
|
81
|
+
*/
|
82
|
+
function getLastCommit() {
|
83
|
+
if (hasTags()) {
|
84
|
+
log.silly("getLastTagInBranch");
|
85
|
+
return childProcess.execSync("git", ["describe", "--tags", "--abbrev=0"]);
|
86
|
+
}
|
87
|
+
log.silly("getFirstCommit");
|
88
|
+
return childProcess.execSync("git", ["rev-list", "--max-parents=0", "HEAD"]);
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* @param {import("@lerna/child-process").ExecOpts} opts
|
93
|
+
*/
|
94
|
+
function hasTags() {
|
95
|
+
let result = false;
|
96
|
+
try {
|
97
|
+
result = !!childProcess.execSync("git", ["tag"]);
|
98
|
+
} catch (err) {
|
99
|
+
log.warn("ENOTAGS", "No git tags were reachable from this branch!");
|
100
|
+
log.verbose("hasTags error", err);
|
101
|
+
}
|
102
|
+
log.verbose("hasTags", result);
|
103
|
+
return result;
|
104
|
+
}
|
105
|
+
|
106
|
+
|
63
107
|
/**
|
64
108
|
* 检查指定工程目录下是否存在变更文件
|
65
109
|
* @param {string} projectPath 目标工程路径
|
66
110
|
* @returns 检查结果
|
67
111
|
*/
|
68
112
|
function checkProjectChanges(projectPath) {
|
113
|
+
const lastCommit = getLastCommit();
|
69
114
|
return childProcess
|
70
115
|
// 使用 git diff 命令查询自上传提交以来,目标工程路径下是否有变更的文件
|
71
|
-
.exec("git", ["diff", "--name-only",
|
116
|
+
.exec("git", ["diff", "--name-only", lastCommit, projectPath])
|
72
117
|
.then((returnValue) => {
|
73
|
-
//
|
118
|
+
// 提取命令输出结果中的文件集合ß
|
74
119
|
const changedFiles = returnValue.stdout.split("\n").filter(Boolean);
|
75
120
|
// 根据文件个数确定是否存在变更
|
76
121
|
const hasChanges = changedFiles.length > 0;
|
77
122
|
if (hasChanges) {
|
78
|
-
console.log(`${projectPath} has changed.`)
|
123
|
+
console.log(`${projectPath} has changed sence last commit ${lastCommit}.`)
|
79
124
|
} else {
|
80
|
-
console.log(`Did not detect any changes from ${projectPath} sence last commit.`)
|
125
|
+
console.log(`Did not detect any changes from ${projectPath} sence last commit ${lastCommit}.`)
|
81
126
|
}
|
82
127
|
// 返回检测结果
|
83
128
|
return hasChanges;
|
@@ -89,7 +134,7 @@ function checkProjectChanges(projectPath) {
|
|
89
134
|
* @param {string} projectPath 目标工程路径
|
90
135
|
* @returns 更新后的版本
|
91
136
|
*/
|
92
|
-
function updateProjectPrereleaseVersion(projectPath
|
137
|
+
function updateProjectPrereleaseVersion(projectPath) {
|
93
138
|
return childProcess
|
94
139
|
// 使用 npm version prerelease 更新指定工程的预发布版本
|
95
140
|
.exec('npm', ['version', 'prerelease', '--preid=beta', '--prefix', projectPath])
|
@@ -99,23 +144,79 @@ function updateProjectPrereleaseVersion(projectPath, projectUrl) {
|
|
99
144
|
const packageConfig = JSON.parse(fs.readFileSync(packageJsonFilePath, 'utf-8'));
|
100
145
|
// 提取更新后的版本
|
101
146
|
const updatedVersion = returnValue.stdout;
|
102
|
-
// 向git缓冲区中添加变更
|
103
|
-
childProcess.execSync('git', ['add', '.']);
|
104
|
-
// 提交变更记录
|
105
|
-
childProcess.execSync('git', ['commit', '-m', `update ${packageConfig.name} prerelease version to ${updatedVersion}. [skip ci]`]);
|
106
147
|
console.log(`update ${packageConfig.name} prerelease version to ${updatedVersion}`);
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
// 提交变更集
|
111
|
-
if (projectUrl) {
|
112
|
-
return childProcess.exec("git", ["push", '-o', 'ci.skip', projectUrl]);
|
113
|
-
} else {
|
114
|
-
return childProcess.exec('git', ['push', '-o', 'ci.skip']);
|
115
|
-
}
|
148
|
+
const updateResult = {};
|
149
|
+
updateResult[packageConfig.name] = updatedVersion;
|
150
|
+
return updateResult;
|
116
151
|
})
|
117
152
|
}
|
118
153
|
|
154
|
+
function builderVersionChangeMessage(prefix, updatedVersions, suffix = '') {
|
155
|
+
const versionMessage = Object.keys(updatedVersions).reduce((latestMessage, packageName, index, originalArray) => {
|
156
|
+
const version = updatedVersions[packageName];
|
157
|
+
let message = `${packageName} to ${version}`;
|
158
|
+
if (index <= originalArray.length - 2) {
|
159
|
+
message = message + ', ';
|
160
|
+
}
|
161
|
+
return latestMessage = latestMessage + message;
|
162
|
+
}, `${prefix} `)
|
163
|
+
return `${versionMessage} ${suffix}`;
|
164
|
+
// const versionMessage = updatedVersions.reduce((latestMessage, updateVersion, index, originalArray) => {
|
165
|
+
// if (Object.keys(updateVersion).length) {
|
166
|
+
// const packageName = Object.keys(updateVersion)[0];
|
167
|
+
// const version = updateVersion[packageName];
|
168
|
+
// let message = `${packageName} to ${version}`;
|
169
|
+
// if (index <= originalArray.length - 2) {
|
170
|
+
// message = message + ', ';
|
171
|
+
// }
|
172
|
+
// latestMessage = latestMessage + message;
|
173
|
+
// }
|
174
|
+
// return latestMessage;
|
175
|
+
// }, `${prefix} `);
|
176
|
+
// return `${versionMessage} ${suffix}`;
|
177
|
+
}
|
178
|
+
|
179
|
+
function commitChanges(updatedVersions, commitUrl) {
|
180
|
+
const commitMessage = builderVersionChangeMessage('Update', updatedVersions, '.');
|
181
|
+
|
182
|
+
if (commitMessage) {
|
183
|
+
// 向git缓冲区中添加变更
|
184
|
+
childProcess.execSync('git', ['add', '.']);
|
185
|
+
// // 提交变更记录
|
186
|
+
childProcess.execSync('git', ['commit', '-m', `${commitMessage} [skip ci]`]);
|
187
|
+
|
188
|
+
console.log(commitMessage);
|
189
|
+
|
190
|
+
const branch = childProcess.execSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
191
|
+
console.log(`executing git push ${branch}`);
|
192
|
+
// 提交变更集
|
193
|
+
if (commitUrl) {
|
194
|
+
return childProcess.exec("git", ["push", '-o', 'ci.skip', commitUrl]);
|
195
|
+
} else {
|
196
|
+
return childProcess.exec('git', ['push', '-o', 'ci.skip']);
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
function buildWorkspace(workspace) {
|
202
|
+
console.log(`executing lerna run build --scope=${workspace.packageName}`)
|
203
|
+
return childProcess.exec('lerna', ['run', 'build', `--scope=${workspace.packageName}`]);
|
204
|
+
// lerna run build --scope=@farris/ide-framework
|
205
|
+
}
|
206
|
+
|
207
|
+
function tagMonoWorkspace(monoWorkspace, commitUrl) {
|
208
|
+
const tagMessage = builderVersionChangeMessage('Publish npm packages ', monoWorkspace.updateResult, '.');
|
209
|
+
const date = moment(new Date());
|
210
|
+
const tagVersion = `v${date.format('yyyyMMddhhmmss')}`;
|
211
|
+
childProcess.execSync('git', ['tag', tagVersion, '-m', tagMessage]);
|
212
|
+
// 提交变更集
|
213
|
+
if (commitUrl) {
|
214
|
+
return childProcess.exec("git", ["push", '-o', 'ci.skip', commitUrl]);
|
215
|
+
} else {
|
216
|
+
return childProcess.exec('git', ['push', '-o', 'ci.skip']);
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
119
220
|
/**
|
120
221
|
* 发布指定路径下的npm包
|
121
222
|
* @param {string} projectPath 目标工程路径
|
@@ -130,3 +231,128 @@ function publish(projectPath) {
|
|
130
231
|
// 调用 npm publish 发布指定路径下的npm包
|
131
232
|
return childProcess.exec('npm', ['publish', packagePath])
|
132
233
|
}
|
234
|
+
|
235
|
+
function publishAll(commitUrl) {
|
236
|
+
const monoRepoProject = new Project(process.cwd());
|
237
|
+
let chain = Promise.resolve();
|
238
|
+
chain = chain.then(() => {
|
239
|
+
return monoRepoProject.getPackages()
|
240
|
+
.then(packages => {
|
241
|
+
const monoWorkspace = { packages };
|
242
|
+
return monoWorkspace;
|
243
|
+
})
|
244
|
+
});
|
245
|
+
chain = chain.then((monoWorkspace) => {
|
246
|
+
const packages = monoWorkspace.packages;
|
247
|
+
monoWorkspace.workspaces = [];
|
248
|
+
monoWorkspace.projects = [];
|
249
|
+
packages.forEach(packageJson => {
|
250
|
+
const workspacePath = packageJson.location;
|
251
|
+
const angularJson = readAngularJson(workspacePath)
|
252
|
+
const workspace = readWorkspace(angularJson, packageJson);
|
253
|
+
monoWorkspace.workspaces.push(workspace);
|
254
|
+
workspace.projects.reduce((monoWorkspace, projectInfo) => {
|
255
|
+
monoWorkspace.projects.push(projectInfo);
|
256
|
+
return monoWorkspace;
|
257
|
+
}, monoWorkspace);
|
258
|
+
// .forEach((projectInfo) => monoWorkspace.projects.push(projectInfo));
|
259
|
+
});
|
260
|
+
return monoWorkspace;
|
261
|
+
});
|
262
|
+
chain = chain.then(monoWorkspace => {
|
263
|
+
const projects = monoWorkspace.projects;
|
264
|
+
const checkProjects = projects.map((projectInfo) => {
|
265
|
+
let checkPromise = checkProjectChanges(projectInfo.project.path);
|
266
|
+
let changedPromise = checkPromise.then(hasChanged => {
|
267
|
+
projectInfo.hasChanged = hasChanged;
|
268
|
+
return Promise.resolve(projectInfo);
|
269
|
+
});
|
270
|
+
return changedPromise;
|
271
|
+
});
|
272
|
+
return Promise.all(checkProjects)
|
273
|
+
.then(changedProjects => {
|
274
|
+
monoWorkspace.changedProjects = changedProjects;
|
275
|
+
return Promise.resolve(monoWorkspace);
|
276
|
+
});
|
277
|
+
});
|
278
|
+
chain = chain.then(monoWorkspace => {
|
279
|
+
const changedProjects = monoWorkspace.changedProjects;
|
280
|
+
const prereleasePromise = changedProjects.map(projectInfo => updateProjectPrereleaseVersion(projectInfo.project.path, monoWorkspace));
|
281
|
+
return Promise.all(prereleasePromise)
|
282
|
+
.then((results) => {
|
283
|
+
results.reduce((workspace, updateResult) => {
|
284
|
+
workspace.updateResult = workspace.updateResult || {};
|
285
|
+
Object.assign(workspace.updateResult, updateResult);
|
286
|
+
return workspace;
|
287
|
+
}, monoWorkspace);
|
288
|
+
const updatedVersions = monoWorkspace.updateResult;
|
289
|
+
commitChanges(updatedVersions, commitUrl);
|
290
|
+
return Promise.resolve(monoWorkspace);
|
291
|
+
});
|
292
|
+
});
|
293
|
+
chain = chain.then(monoWorkspace => {
|
294
|
+
const buildPromises = monoWorkspace.workspaces.map((workspace) => buildWorkspace(workspace));
|
295
|
+
return Promise.all(buildPromises)
|
296
|
+
.then((results) => {
|
297
|
+
return Promise.resolve(monoWorkspace);
|
298
|
+
});
|
299
|
+
});
|
300
|
+
chain = chain.then(monoWorkspace => {
|
301
|
+
const changedProjects = monoWorkspace.changedProjects;
|
302
|
+
const publishPromises = changedProjects.map(projectInfo => publish(projectInfo.project.path));
|
303
|
+
Promise.all(publishPromises)
|
304
|
+
.then(() => {
|
305
|
+
return tagMonoWorkspace(monoWorkspace, commitUrl);
|
306
|
+
});
|
307
|
+
});
|
308
|
+
}
|
309
|
+
|
310
|
+
function readAngularJson(workspacePath) {
|
311
|
+
const angularJsonPath = path.normalize(`${workspacePath}/angular.json`);
|
312
|
+
return JSON.parse(fs.readFileSync(angularJsonPath, 'utf-8'));
|
313
|
+
}
|
314
|
+
|
315
|
+
function readWorkspace(angularJson, packageJson) {
|
316
|
+
const projects = angularJson.projects;
|
317
|
+
const workspacePath = packageJson.location;
|
318
|
+
const packageName = packageJson.name;
|
319
|
+
const workspace = {
|
320
|
+
packageName,
|
321
|
+
path: workspacePath,
|
322
|
+
projects: []
|
323
|
+
};
|
324
|
+
Object.keys(projects)
|
325
|
+
.reduce((workspace, projectName) => {
|
326
|
+
const projectInfo = readProjectInfo(projectName, projects[projectName], workspacePath);
|
327
|
+
if (projectInfo) {
|
328
|
+
// workspace.set(projectName, projectInfo);
|
329
|
+
workspace.projects.push(projectInfo);
|
330
|
+
}
|
331
|
+
return workspace;
|
332
|
+
}, workspace);
|
333
|
+
return workspace;
|
334
|
+
}
|
335
|
+
|
336
|
+
function readProjectInfo(projectName, project, workspacePath) {
|
337
|
+
const projectPath = path.normalize(`${workspacePath}/${project.root}`);
|
338
|
+
const projectType = project.projectType;
|
339
|
+
if (projectType === 'library') {
|
340
|
+
const packageJsonPath = path.normalize(`${projectPath}/package.json`);
|
341
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
342
|
+
const packageName = packageJson.name;
|
343
|
+
const ngPackagePath = path.normalize(`${projectPath}/ng-package.json`);
|
344
|
+
const ngPackage = JSON.parse(fs.readFileSync(ngPackagePath, 'utf-8'));
|
345
|
+
const packagePath = path.normalize(`${projectPath}/${ngPackage.dest}`);
|
346
|
+
return {
|
347
|
+
project: {
|
348
|
+
name: projectName,
|
349
|
+
path: projectPath,
|
350
|
+
type: projectType
|
351
|
+
},
|
352
|
+
package: {
|
353
|
+
name: packageName,
|
354
|
+
path: packagePath
|
355
|
+
}
|
356
|
+
}
|
357
|
+
}
|
358
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@farris/cli",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.11",
|
4
4
|
"description": "Farris command line interface",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
@@ -20,6 +20,7 @@
|
|
20
20
|
"author": "Sagi Chen",
|
21
21
|
"license": "ISC",
|
22
22
|
"dependencies": {
|
23
|
-
"lerna": "^4.0.0"
|
23
|
+
"lerna": "^4.0.0",
|
24
|
+
"moment": "^2.29.3"
|
24
25
|
}
|
25
26
|
}
|