@farris/cli 1.0.8 → 1.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/ci/cli.js +246 -20
  2. 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 project = argv.project;
21
- checkProjectChanges(project);
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", "HEAD^", projectPath])
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, projectUrl) {
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
- const branch = childProcess.execSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
109
- console.log(`executing git push ${branch}`);
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.8",
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
  }