@farris/cli 1.0.7 → 1.0.10

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 +231 -19
  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,8 @@ function checkProjectChanges(projectPath) {
89
134
  * @param {string} projectPath 目标工程路径
90
135
  * @returns 更新后的版本
91
136
  */
92
- function updateProjectPrereleaseVersion(projectPath, projectUrl) {
137
+ function updateProjectPrereleaseVersion(projectPath, monoWorkspace) {
138
+ monoWorkspace.updateResult = monoWorkspace.updateResult || {};
93
139
  return childProcess
94
140
  // 使用 npm version prerelease 更新指定工程的预发布版本
95
141
  .exec('npm', ['version', 'prerelease', '--preid=beta', '--prefix', projectPath])
@@ -99,21 +145,67 @@ function updateProjectPrereleaseVersion(projectPath, projectUrl) {
99
145
  const packageConfig = JSON.parse(fs.readFileSync(packageJsonFilePath, 'utf-8'));
100
146
  // 提取更新后的版本
101
147
  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}`]);
106
148
  console.log(`update ${packageConfig.name} prerelease version to ${updatedVersion}`);
149
+ monoWorkspace.updateResult[packageConfig.name] = updatedVersion;
150
+ return monoWorkspace;
151
+ })
152
+ }
107
153
 
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", projectUrl]);
113
- } else {
114
- return childProcess.exec('git', ['push']);
154
+ function builderVersionChangeMessage(prefix, updatedVersions, suffix = '') {
155
+ const versionMessage = updatedVersions.reduce((latestMessage, updateVersion, index, originalArray) => {
156
+ if (Object.keys(updateVersion).length) {
157
+ const packageName = Object.keys(updateVersion)[0];
158
+ const version = updateVersion[packageName];
159
+ let message = `${packageName} to ${version}`;
160
+ if (index <= originalArray.length - 2) {
161
+ message = message + ', ';
115
162
  }
116
- })
163
+ latestMessage = latestMessage + message;
164
+ }
165
+ return latestMessage;
166
+ }, `${prefix} `);
167
+ return `${versionMessage} ${suffix}ß`;
168
+ }
169
+
170
+ function commitChanges(updatedVersions, commitUrl) {
171
+ const commitMessage = builderVersionChangeMessage('Update', updatedVersions, '.');
172
+
173
+ if (commitMessage) {
174
+ // 向git缓冲区中添加变更
175
+ childProcess.execSync('git', ['add', '.']);
176
+ // // 提交变更记录
177
+ childProcess.execSync('git', ['commit', '-m', `${commitMessage} [skip ci]`]);
178
+
179
+ console.log(commitMessage);
180
+
181
+ const branch = childProcess.execSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
182
+ console.log(`executing git push ${branch}`);
183
+ // 提交变更集
184
+ if (commitUrl) {
185
+ return childProcess.exec("git", ["push", '-o', 'ci.skip', commitUrl]);
186
+ } else {
187
+ return childProcess.exec('git', ['push', '-o', 'ci.skip']);
188
+ }
189
+ }
190
+ }
191
+
192
+ function buildWorkspace(workspace) {
193
+ return childProcess.exec('lerna', ['run', 'build', `--scope=${workspace.packageName}`]);
194
+ // lerna run build --scope=@farris/ide-framework
195
+ }
196
+
197
+ function tagMonoWorkspace(monoWorkspace, commitUrl) {
198
+ const tagMessage = builderVersionChangeMessage('Publish npm packages ', monoWorkspace.updateResult, '.');
199
+ /*from www.w3cschool.cn*/
200
+ const date = moment(new Date());
201
+ const tagVersion = `v${date.format('yyyyMMddhhmmss')}`;
202
+ childProcess.execSync('git', ['tag', tagVersion, '-m', tagMessage]);
203
+ // 提交变更集
204
+ if (commitUrl) {
205
+ return childProcess.exec("git", ["push", '-o', 'ci.skip', commitUrl]);
206
+ } else {
207
+ return childProcess.exec('git', ['push', '-o', 'ci.skip']);
208
+ }
117
209
  }
118
210
 
119
211
  /**
@@ -130,3 +222,123 @@ function publish(projectPath) {
130
222
  // 调用 npm publish 发布指定路径下的npm包
131
223
  return childProcess.exec('npm', ['publish', packagePath])
132
224
  }
225
+
226
+ function publishAll(commitUrl) {
227
+ const monoRepoProject = new Project(process.cwd());
228
+ let chain = Promise.resolve();
229
+ chain = chain.then(() => {
230
+ return monoRepoProject.getPackages()
231
+ .then(packages => {
232
+ const monoWorkspace = { packages };
233
+ return monoWorkspace;
234
+ })
235
+ });
236
+ chain = chain.then((monoWorkspace) => {
237
+ const packages = monoWorkspace.packages;
238
+ monoWorkspace.workspaces = [];
239
+ monoWorkspace.projects = [];
240
+ packages.forEach(packageJson => {
241
+ const workspacePath = packageJson.location;
242
+ const angularJson = readAngularJson(workspacePath)
243
+ const workspace = readWorkspace(angularJson, packageJson);
244
+ monoWorkspace.workspaces.push(workspace);
245
+ workspace.projects.reduce((monoWorkspace, projectInfo) => {
246
+ monoWorkspace.projects.push(projectInfo);
247
+ return monoWorkspace;
248
+ }, monoWorkspace);
249
+ // .forEach((projectInfo) => monoWorkspace.projects.push(projectInfo));
250
+ });
251
+ return monoWorkspace;
252
+ });
253
+ chain = chain.then(monoWorkspace => {
254
+ const projects = monoWorkspace.projects;
255
+ const checkProjects = projects.map((projectInfo) => {
256
+ let checkPromise = checkProjectChanges(projectInfo.project.path);
257
+ let changedPromise = checkPromise.then(hasChanged => {
258
+ projectInfo.hasChanged = hasChanged;
259
+ return Promise.resolve(projectInfo);
260
+ });
261
+ return changedPromise;
262
+ });
263
+ return Promise.all(checkProjects)
264
+ .then(changedProjects => {
265
+ monoWorkspace.changedProjects = changedProjects;
266
+ return Promise.resolve(monoWorkspace);
267
+ });
268
+ });
269
+ chain = chain.then(monoWorkspace => {
270
+ const changedProjects = monoWorkspace.changedProjects;
271
+ const prereleasePromise = changedProjects.map(projectInfo => updateProjectPrereleaseVersion(projectInfo.project.path, monoWorkspace));
272
+ return Promise.all(prereleasePromise)
273
+ .then((monoWorkspace) => {
274
+ const updatedVersions = monoWorkspace.updateResult;
275
+ commitChanges(updatedVersions, commitUrl);
276
+ return Promise.resolve(monoWorkspace);
277
+ });
278
+ });
279
+ chain = chain.then(monoWorkspace => {
280
+ const buildPromises = monoWorkspace.workspaces.map((workspace) => buildWorkspace(workspace));
281
+ return Promise.all(buildPromises)
282
+ .then(() => {
283
+ return Promise.resolve(monoWorkspace);
284
+ });
285
+ });
286
+ chain = chain.then(monoWorkspace => {
287
+ const changedProjects = monoWorkspace.changedProjects;
288
+ const publishPromises = changedProjects.map(projectInfo => publish(projectInfo.project.path));
289
+ Promise.all(publishPromises)
290
+ .then(() => {
291
+ return tagMonoWorkspace(monoWorkspace, commitUrl);
292
+ });
293
+ });
294
+ }
295
+
296
+ function readAngularJson(workspacePath) {
297
+ const angularJsonPath = path.normalize(`${workspacePath}/angular.json`);
298
+ return JSON.parse(fs.readFileSync(angularJsonPath, 'utf-8'));
299
+ }
300
+
301
+ function readWorkspace(angularJson, packageJson) {
302
+ const projects = angularJson.projects;
303
+ const workspacePath = packageJson.location;
304
+ const packageName = packageJson.name;
305
+ const workspace = {
306
+ packageName,
307
+ path: workspacePath,
308
+ projects: []
309
+ };
310
+ Object.keys(projects)
311
+ .reduce((workspace, projectName) => {
312
+ const projectInfo = readProjectInfo(projectName, projects[projectName], workspacePath);
313
+ if (projectInfo) {
314
+ // workspace.set(projectName, projectInfo);
315
+ workspace.projects.push(projectInfo);
316
+ }
317
+ return workspace;
318
+ }, workspace);
319
+ return workspace;
320
+ }
321
+
322
+ function readProjectInfo(projectName, project, workspacePath) {
323
+ const projectPath = path.normalize(`${workspacePath}/${project.root}`);
324
+ const projectType = project.projectType;
325
+ if (projectType === 'library') {
326
+ const packageJsonPath = path.normalize(`${projectPath}/package.json`);
327
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
328
+ const packageName = packageJson.name;
329
+ const ngPackagePath = path.normalize(`${projectPath}/ng-package.json`);
330
+ const ngPackage = JSON.parse(fs.readFileSync(ngPackagePath, 'utf-8'));
331
+ const packagePath = path.normalize(`${projectPath}/${ngPackage.dest}`);
332
+ return {
333
+ project: {
334
+ name: projectName,
335
+ path: projectPath,
336
+ type: projectType
337
+ },
338
+ package: {
339
+ name: packageName,
340
+ path: packagePath
341
+ }
342
+ }
343
+ }
344
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farris/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.10",
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
  }