1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const core_1 = require("@angular-devkit/core");
|
11 | const node_1 = require("@angular-devkit/core/node");
|
12 | const schematics_1 = require("@angular-devkit/schematics");
|
13 | const tools_1 = require("@angular-devkit/schematics/tools");
|
14 | const child_process_1 = require("child_process");
|
15 | const fs = require("fs");
|
16 | const path = require("path");
|
17 | const semver = require("semver");
|
18 | const schema_1 = require("../lib/config/schema");
|
19 | const command_1 = require("../models/command");
|
20 | const install_package_1 = require("../tasks/install-package");
|
21 | const color_1 = require("../utilities/color");
|
22 | const log_file_1 = require("../utilities/log-file");
|
23 | const package_manager_1 = require("../utilities/package-manager");
|
24 | const package_metadata_1 = require("../utilities/package-metadata");
|
25 | const package_tree_1 = require("../utilities/package-tree");
|
26 | const npa = require('npm-package-arg');
|
27 | const pickManifest = require('npm-pick-manifest');
|
28 | const oldConfigFileNames = ['.angular-cli.json', 'angular-cli.json'];
|
29 | const NG_VERSION_9_POST_MSG = color_1.colors.cyan('\nYour project has been updated to Angular version 9!\n' +
|
30 | 'For more info, please see: https://v9.angular.io/guide/updating-to-version-9');
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | const disableVersionCheckEnv = process.env['NG_DISABLE_VERSION_CHECK'];
|
36 | const disableVersionCheck = disableVersionCheckEnv !== undefined &&
|
37 | disableVersionCheckEnv !== '0' &&
|
38 | disableVersionCheckEnv.toLowerCase() !== 'false';
|
39 | class UpdateCommand extends command_1.Command {
|
40 | constructor() {
|
41 | super(...arguments);
|
42 | this.allowMissingWorkspace = true;
|
43 | }
|
44 | async initialize() {
|
45 | this.packageManager = await package_manager_1.getPackageManager(this.workspace.root);
|
46 | this.workflow = new tools_1.NodeWorkflow(new core_1.virtualFs.ScopedHost(new node_1.NodeJsSyncHost(), core_1.normalize(this.workspace.root)), {
|
47 | packageManager: this.packageManager,
|
48 | root: core_1.normalize(this.workspace.root),
|
49 |
|
50 |
|
51 | resolvePaths: [__dirname, this.workspace.root],
|
52 | });
|
53 | this.workflow.engineHost.registerOptionsTransform(tools_1.validateOptionsWithSchema(this.workflow.registry));
|
54 | }
|
55 | async executeSchematic(collection, schematic, options = {}) {
|
56 | let error = false;
|
57 | let logs = [];
|
58 | const files = new Set();
|
59 | const reporterSubscription = this.workflow.reporter.subscribe(event => {
|
60 |
|
61 | const eventPath = event.path.startsWith('/') ? event.path.substr(1) : event.path;
|
62 | switch (event.kind) {
|
63 | case 'error':
|
64 | error = true;
|
65 | const desc = event.description == 'alreadyExist' ? 'already exists' : 'does not exist.';
|
66 | this.logger.error(`ERROR! ${eventPath} ${desc}.`);
|
67 | break;
|
68 | case 'update':
|
69 | logs.push(`${color_1.colors.whiteBright('UPDATE')} ${eventPath} (${event.content.length} bytes)`);
|
70 | files.add(eventPath);
|
71 | break;
|
72 | case 'create':
|
73 | logs.push(`${color_1.colors.green('CREATE')} ${eventPath} (${event.content.length} bytes)`);
|
74 | files.add(eventPath);
|
75 | break;
|
76 | case 'delete':
|
77 | logs.push(`${color_1.colors.yellow('DELETE')} ${eventPath}`);
|
78 | files.add(eventPath);
|
79 | break;
|
80 | case 'rename':
|
81 | const eventToPath = event.to.startsWith('/') ? event.to.substr(1) : event.to;
|
82 | logs.push(`${color_1.colors.blue('RENAME')} ${eventPath} => ${eventToPath}`);
|
83 | files.add(eventPath);
|
84 | break;
|
85 | }
|
86 | });
|
87 | const lifecycleSubscription = this.workflow.lifeCycle.subscribe(event => {
|
88 | if (event.kind == 'end' || event.kind == 'post-tasks-start') {
|
89 | if (!error) {
|
90 |
|
91 | logs.forEach(log => this.logger.info(log));
|
92 | logs = [];
|
93 | }
|
94 | }
|
95 | });
|
96 |
|
97 | try {
|
98 | await this.workflow
|
99 | .execute({
|
100 | collection,
|
101 | schematic,
|
102 | options,
|
103 | logger: this.logger,
|
104 | })
|
105 | .toPromise();
|
106 | reporterSubscription.unsubscribe();
|
107 | lifecycleSubscription.unsubscribe();
|
108 | return { success: !error, files };
|
109 | }
|
110 | catch (e) {
|
111 | if (e instanceof schematics_1.UnsuccessfulWorkflowExecution) {
|
112 | this.logger.error(`${color_1.colors.symbols.cross} Migration failed. See above for further details.\n`);
|
113 | }
|
114 | else {
|
115 | const logPath = log_file_1.writeErrorToLogFile(e);
|
116 | this.logger.fatal(`${color_1.colors.symbols.cross} Migration failed: ${e.message}\n` +
|
117 | ` See "${logPath}" for further details.\n`);
|
118 | }
|
119 | return { success: false, files };
|
120 | }
|
121 | }
|
122 | |
123 |
|
124 |
|
125 | async executeMigration(packageName, collectionPath, migrationName, commit) {
|
126 | const collection = this.workflow.engine.createCollection(collectionPath);
|
127 | const name = collection.listSchematicNames().find(name => name === migrationName);
|
128 | if (!name) {
|
129 | this.logger.error(`Cannot find migration '${migrationName}' in '${packageName}'.`);
|
130 | return false;
|
131 | }
|
132 | const schematic = this.workflow.engine.createSchematic(name, collection);
|
133 | this.logger.info(color_1.colors.cyan(`** Executing '${migrationName}' of package '${packageName}' **\n`));
|
134 | return this.executePackageMigrations([schematic.description], packageName, commit);
|
135 | }
|
136 | |
137 |
|
138 |
|
139 | async executeMigrations(packageName, collectionPath, range, commit) {
|
140 | const collection = this.workflow.engine.createCollection(collectionPath);
|
141 | const migrations = [];
|
142 | for (const name of collection.listSchematicNames()) {
|
143 | const schematic = this.workflow.engine.createSchematic(name, collection);
|
144 | const description = schematic.description;
|
145 | description.version = coerceVersionNumber(description.version) || undefined;
|
146 | if (!description.version) {
|
147 | continue;
|
148 | }
|
149 | if (semver.satisfies(description.version, range, { includePrerelease: true })) {
|
150 | migrations.push(description);
|
151 | }
|
152 | }
|
153 | migrations.sort((a, b) => semver.compare(a.version, b.version) || a.name.localeCompare(b.name));
|
154 | if (migrations.length === 0) {
|
155 | return true;
|
156 | }
|
157 | this.logger.info(color_1.colors.cyan(`** Executing migrations of package '${packageName}' **\n`));
|
158 | return this.executePackageMigrations(migrations, packageName, commit);
|
159 | }
|
160 |
|
161 | async executePackageMigrations(migrations, packageName, commit = false) {
|
162 | for (const migration of migrations) {
|
163 | this.logger.info(`${color_1.colors.symbols.pointer} ${migration.description.replace(/\. /g, '.\n ')}`);
|
164 | const result = await this.executeSchematic(migration.collection.name, migration.name);
|
165 | if (!result.success) {
|
166 | return false;
|
167 | }
|
168 | this.logger.info(' Migration completed.');
|
169 |
|
170 | if (commit) {
|
171 | const commitPrefix = `${packageName} migration - ${migration.name}`;
|
172 | const commitMessage = migration.description
|
173 | ? `${commitPrefix}\n${migration.description}`
|
174 | : commitPrefix;
|
175 | const committed = this.commit(commitMessage);
|
176 | if (!committed) {
|
177 |
|
178 | return false;
|
179 | }
|
180 | }
|
181 | this.logger.info('');
|
182 | }
|
183 | return true;
|
184 | }
|
185 |
|
186 | async run(options) {
|
187 |
|
188 |
|
189 |
|
190 | try {
|
191 | require.resolve('@angular-devkit/schematics', { paths: [this.workspace.root] });
|
192 | }
|
193 | catch (e) {
|
194 | if (e.code === 'MODULE_NOT_FOUND') {
|
195 | this.logger.fatal('The "@angular-devkit/schematics" package cannot be resolved from the workspace root directory. ' +
|
196 | 'This may be due to an unsupported node modules structure.\n' +
|
197 | 'Please remove both the "node_modules" directory and the package lock file; and then reinstall.\n' +
|
198 | 'If this does not correct the problem, ' +
|
199 | 'please temporarily install the "@angular-devkit/schematics" package within the workspace. ' +
|
200 | 'It can be removed once the update is complete.');
|
201 | return 1;
|
202 | }
|
203 | throw e;
|
204 | }
|
205 |
|
206 | if (!disableVersionCheck && await this.checkCLILatestVersion(options.verbose, options.next)) {
|
207 | this.logger.warn(`The installed local Angular CLI version is older than the latest ${options.next ? 'pre-release' : 'stable'} version.\n` +
|
208 | 'Installing a temporary version to perform the update.');
|
209 | return install_package_1.runTempPackageBin(`@angular/cli@${options.next ? 'next' : 'latest'}`, this.logger, this.packageManager, process.argv.slice(2));
|
210 | }
|
211 | const packages = [];
|
212 | for (const request of options['--'] || []) {
|
213 | try {
|
214 | const packageIdentifier = npa(request);
|
215 |
|
216 | if (!packageIdentifier.registry) {
|
217 | this.logger.error(`Package '${request}' is not a registry package identifer.`);
|
218 | return 1;
|
219 | }
|
220 | if (packages.some(v => v.name === packageIdentifier.name)) {
|
221 | this.logger.error(`Duplicate package '${packageIdentifier.name}' specified.`);
|
222 | return 1;
|
223 | }
|
224 | if (options.migrateOnly && packageIdentifier.rawSpec) {
|
225 | this.logger.warn('Package specifier has no effect when using "migrate-only" option.');
|
226 | }
|
227 |
|
228 | if (options.next && !packageIdentifier.rawSpec) {
|
229 | packageIdentifier.fetchSpec = 'next';
|
230 | }
|
231 | packages.push(packageIdentifier);
|
232 | }
|
233 | catch (e) {
|
234 | this.logger.error(e.message);
|
235 | return 1;
|
236 | }
|
237 | }
|
238 | if (options.all && packages.length > 0) {
|
239 | this.logger.error('Cannot specify packages when using the "all" option.');
|
240 | return 1;
|
241 | }
|
242 | else if (options.all && options.migrateOnly) {
|
243 | this.logger.error('Cannot use "all" option with "migrate-only" option.');
|
244 | return 1;
|
245 | }
|
246 | else if (!options.migrateOnly && (options.from || options.to)) {
|
247 | this.logger.error('Can only use "from" or "to" options with "migrate-only" option.');
|
248 | return 1;
|
249 | }
|
250 |
|
251 |
|
252 | const statusCheck = packages.length === 0 && !options.all;
|
253 | if (!statusCheck && !this.checkCleanGit()) {
|
254 | if (options.allowDirty) {
|
255 | this.logger.warn('Repository is not clean. Update changes will be mixed with pre-existing changes.');
|
256 | }
|
257 | else {
|
258 | this.logger.error('Repository is not clean. Please commit or stash any changes before updating.');
|
259 | return 2;
|
260 | }
|
261 | }
|
262 | this.logger.info(`Using package manager: '${this.packageManager}'`);
|
263 |
|
264 | if (options.migrateOnly === undefined &&
|
265 | options.from === undefined &&
|
266 | !options.all &&
|
267 | packages.length === 1 &&
|
268 | packages[0].name === '@angular/cli' &&
|
269 | this.workspace.configFile &&
|
270 | oldConfigFileNames.includes(this.workspace.configFile)) {
|
271 | options.migrateOnly = true;
|
272 | options.from = '1.0.0';
|
273 | }
|
274 | this.logger.info('Collecting installed dependencies...');
|
275 | const packageTree = await package_tree_1.readPackageTree(this.workspace.root);
|
276 | const rootDependencies = package_tree_1.findNodeDependencies(packageTree);
|
277 | this.logger.info(`Found ${Object.keys(rootDependencies).length} dependencies.`);
|
278 | if (options.all) {
|
279 |
|
280 |
|
281 | for (const dep of Object.keys(rootDependencies)) {
|
282 | const packageIdentifier = npa(dep);
|
283 | if (options.next) {
|
284 | packageIdentifier.fetchSpec = 'next';
|
285 | }
|
286 | packages.push(packageIdentifier);
|
287 | }
|
288 | }
|
289 | else if (packages.length === 0) {
|
290 |
|
291 | const { success } = await this.executeSchematic('@schematics/update', 'update', {
|
292 | force: options.force || false,
|
293 | next: options.next || false,
|
294 | verbose: options.verbose || false,
|
295 | packageManager: this.packageManager,
|
296 | packages: options.all ? Object.keys(rootDependencies) : [],
|
297 | });
|
298 | return success ? 0 : 1;
|
299 | }
|
300 | if (options.migrateOnly) {
|
301 | if (!options.from && typeof options.migrateOnly !== 'string') {
|
302 | this.logger.error('"from" option is required when using the "migrate-only" option without a migration name.');
|
303 | return 1;
|
304 | }
|
305 | else if (packages.length !== 1) {
|
306 | this.logger.error('A single package must be specified when using the "migrate-only" option.');
|
307 | return 1;
|
308 | }
|
309 | if (options.next) {
|
310 | this.logger.warn('"next" option has no effect when using "migrate-only" option.');
|
311 | }
|
312 | const packageName = packages[0].name;
|
313 | const packageDependency = rootDependencies[packageName];
|
314 | let packageNode = packageDependency && packageDependency.node;
|
315 | if (packageDependency && !packageNode) {
|
316 | this.logger.error('Package found in package.json but is not installed.');
|
317 | return 1;
|
318 | }
|
319 | else if (!packageDependency) {
|
320 |
|
321 |
|
322 |
|
323 | const child = packageTree.children.find(c => c.name === packageName);
|
324 | if (child) {
|
325 | packageNode = child;
|
326 | }
|
327 | }
|
328 | if (!packageNode) {
|
329 | this.logger.error('Package is not installed.');
|
330 | return 1;
|
331 | }
|
332 | const updateMetadata = packageNode.package['ng-update'];
|
333 | let migrations = updateMetadata && updateMetadata.migrations;
|
334 | if (migrations === undefined) {
|
335 | this.logger.error('Package does not provide migrations.');
|
336 | return 1;
|
337 | }
|
338 | else if (typeof migrations !== 'string') {
|
339 | this.logger.error('Package contains a malformed migrations field.');
|
340 | return 1;
|
341 | }
|
342 | else if (path.posix.isAbsolute(migrations) || path.win32.isAbsolute(migrations)) {
|
343 | this.logger.error('Package contains an invalid migrations field. Absolute paths are not permitted.');
|
344 | return 1;
|
345 | }
|
346 |
|
347 | migrations = migrations.replace(/\\/g, '/');
|
348 | if (migrations.startsWith('../')) {
|
349 | this.logger.error('Package contains an invalid migrations field. ' +
|
350 | 'Paths outside the package root are not permitted.');
|
351 | return 1;
|
352 | }
|
353 |
|
354 | const localMigrations = path.join(packageNode.path, migrations);
|
355 | if (fs.existsSync(localMigrations)) {
|
356 | migrations = localMigrations;
|
357 | }
|
358 | else {
|
359 |
|
360 |
|
361 | try {
|
362 | migrations = require.resolve(migrations, { paths: [packageNode.path] });
|
363 | }
|
364 | catch (e) {
|
365 | if (e.code === 'MODULE_NOT_FOUND') {
|
366 | this.logger.error('Migrations for package were not found.');
|
367 | }
|
368 | else {
|
369 | this.logger.error(`Unable to resolve migrations for package. [${e.message}]`);
|
370 | }
|
371 | return 1;
|
372 | }
|
373 | }
|
374 | let success = false;
|
375 | if (typeof options.migrateOnly == 'string') {
|
376 | success = await this.executeMigration(packageName, migrations, options.migrateOnly, options.createCommits);
|
377 | }
|
378 | else {
|
379 | const from = coerceVersionNumber(options.from);
|
380 | if (!from) {
|
381 | this.logger.error(`"from" value [${options.from}] is not a valid version.`);
|
382 | return 1;
|
383 | }
|
384 | const migrationRange = new semver.Range('>' + from + ' <=' + (options.to || packageNode.package.version));
|
385 | success = await this.executeMigrations(packageName, migrations, migrationRange, options.createCommits);
|
386 | }
|
387 | if (success) {
|
388 | if (packageName === '@angular/core'
|
389 | && options.from
|
390 | && +options.from.split('.')[0] < 9
|
391 | && (options.to || packageNode.package.version).split('.')[0] === '9') {
|
392 | this.logger.info(NG_VERSION_9_POST_MSG);
|
393 | }
|
394 | return 0;
|
395 | }
|
396 | return 1;
|
397 | }
|
398 | const requests = [];
|
399 |
|
400 | for (const pkg of packages) {
|
401 | const node = rootDependencies[pkg.name] && rootDependencies[pkg.name].node;
|
402 | if (!node) {
|
403 | this.logger.error(`Package '${pkg.name}' is not a dependency.`);
|
404 | return 1;
|
405 | }
|
406 |
|
407 | if (pkg.type === 'version' && node.package.version === pkg.fetchSpec) {
|
408 | this.logger.info(`Package '${pkg.name}' is already at '${pkg.fetchSpec}'.`);
|
409 | continue;
|
410 | }
|
411 | requests.push({ identifier: pkg, node });
|
412 | }
|
413 | if (requests.length === 0) {
|
414 | return 0;
|
415 | }
|
416 | const packagesToUpdate = [];
|
417 | this.logger.info('Fetching dependency metadata from registry...');
|
418 | for (const { identifier: requestIdentifier, node } of requests) {
|
419 | const packageName = requestIdentifier.name;
|
420 | let metadata;
|
421 | try {
|
422 |
|
423 |
|
424 | metadata = await package_metadata_1.fetchPackageMetadata(packageName, this.logger, {
|
425 | verbose: options.verbose,
|
426 | });
|
427 | }
|
428 | catch (e) {
|
429 | this.logger.error(`Error fetching metadata for '${packageName}': ` + e.message);
|
430 | return 1;
|
431 | }
|
432 |
|
433 |
|
434 | let manifest;
|
435 | if (requestIdentifier.type === 'version' ||
|
436 | requestIdentifier.type === 'range' ||
|
437 | requestIdentifier.type === 'tag') {
|
438 | try {
|
439 | manifest = pickManifest(metadata, requestIdentifier.fetchSpec);
|
440 | }
|
441 | catch (e) {
|
442 | if (e.code === 'ETARGET') {
|
443 |
|
444 |
|
445 | if (requestIdentifier.type === 'tag' &&
|
446 | requestIdentifier.fetchSpec === 'next' &&
|
447 | !requestIdentifier.rawSpec) {
|
448 | try {
|
449 | manifest = pickManifest(metadata, 'latest');
|
450 | }
|
451 | catch (e) {
|
452 | if (e.code !== 'ETARGET' && e.code !== 'ENOVERSIONS') {
|
453 | throw e;
|
454 | }
|
455 | }
|
456 | }
|
457 | }
|
458 | else if (e.code !== 'ENOVERSIONS') {
|
459 | throw e;
|
460 | }
|
461 | }
|
462 | }
|
463 | if (!manifest) {
|
464 | this.logger.error(`Package specified by '${requestIdentifier.raw}' does not exist within the registry.`);
|
465 | return 1;
|
466 | }
|
467 | if (manifest.version === node.package.version) {
|
468 | this.logger.info(`Package '${packageName}' is already up to date.`);
|
469 | continue;
|
470 | }
|
471 | packagesToUpdate.push(requestIdentifier.toString());
|
472 | }
|
473 | if (packagesToUpdate.length === 0) {
|
474 | return 0;
|
475 | }
|
476 | const { success } = await this.executeSchematic('@schematics/update', 'update', {
|
477 | verbose: options.verbose || false,
|
478 | force: options.force || false,
|
479 | next: !!options.next,
|
480 | packageManager: this.packageManager,
|
481 | packages: packagesToUpdate,
|
482 | migrateExternal: true,
|
483 | });
|
484 | if (success && options.createCommits) {
|
485 | const committed = this.commit(`Angular CLI update for packages - ${packagesToUpdate.join(', ')}`);
|
486 | if (!committed) {
|
487 | return 1;
|
488 | }
|
489 | }
|
490 |
|
491 |
|
492 | const migrations = global.externalMigrations;
|
493 | if (success && migrations) {
|
494 | for (const migration of migrations) {
|
495 | const result = await this.executeMigrations(migration.package, migration.collection, new semver.Range('>' + migration.from + ' <=' + migration.to), options.createCommits);
|
496 | if (!result) {
|
497 | return 0;
|
498 | }
|
499 | }
|
500 | if (migrations.some(m => m.package === '@angular/core' && m.to.split('.')[0] === '9' && +m.from.split('.')[0] < 9)) {
|
501 | this.logger.info(NG_VERSION_9_POST_MSG);
|
502 | }
|
503 | }
|
504 | return success ? 0 : 1;
|
505 | }
|
506 | |
507 |
|
508 |
|
509 | commit(message) {
|
510 |
|
511 | let commitNeeded;
|
512 | try {
|
513 | commitNeeded = hasChangesToCommit();
|
514 | }
|
515 | catch (err) {
|
516 | this.logger.error(` Failed to read Git tree:\n${err.stderr}`);
|
517 | return false;
|
518 | }
|
519 | if (!commitNeeded) {
|
520 | this.logger.info(' No changes to commit after migration.');
|
521 | return true;
|
522 | }
|
523 |
|
524 | try {
|
525 | createCommit(message);
|
526 | }
|
527 | catch (err) {
|
528 | this.logger.error(`Failed to commit update (${message}):\n${err.stderr}`);
|
529 | return false;
|
530 | }
|
531 |
|
532 | const hash = findCurrentGitSha();
|
533 | const shortMessage = message.split('\n')[0];
|
534 | if (hash) {
|
535 | this.logger.info(` Committed migration step (${getShortHash(hash)}): ${shortMessage}.`);
|
536 | }
|
537 | else {
|
538 |
|
539 |
|
540 | this.logger.info(` Committed migration step: ${shortMessage}.`);
|
541 | this.logger.warn(' Failed to look up hash of most recent commit, continuing anyways.');
|
542 | }
|
543 | return true;
|
544 | }
|
545 | checkCleanGit() {
|
546 | try {
|
547 | const topLevel = child_process_1.execSync('git rev-parse --show-toplevel', { encoding: 'utf8', stdio: 'pipe' });
|
548 | const result = child_process_1.execSync('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' });
|
549 | if (result.trim().length === 0) {
|
550 | return true;
|
551 | }
|
552 |
|
553 | for (const entry of result.split('\n')) {
|
554 | const relativeEntry = path.relative(path.resolve(this.workspace.root), path.resolve(topLevel.trim(), entry.slice(3).trim()));
|
555 | if (!relativeEntry.startsWith('..') && !path.isAbsolute(relativeEntry)) {
|
556 | return false;
|
557 | }
|
558 | }
|
559 | }
|
560 | catch (_a) { }
|
561 | return true;
|
562 | }
|
563 | |
564 |
|
565 |
|
566 |
|
567 | async checkCLILatestVersion(verbose = false, next = false) {
|
568 | const { version: installedCLIVersion } = require('../package.json');
|
569 | const LatestCLIManifest = await package_metadata_1.fetchPackageManifest(`@angular/cli@${next ? 'next' : 'latest'}`, this.logger, {
|
570 | verbose,
|
571 | usingYarn: this.packageManager === schema_1.PackageManager.Yarn,
|
572 | });
|
573 | return semver.lt(installedCLIVersion, LatestCLIManifest.version);
|
574 | }
|
575 | }
|
576 | exports.UpdateCommand = UpdateCommand;
|
577 |
|
578 |
|
579 |
|
580 | function hasChangesToCommit() {
|
581 |
|
582 | const files = child_process_1.execSync('git ls-files -m -d -o --exclude-standard').toString();
|
583 |
|
584 | return files !== '';
|
585 | }
|
586 |
|
587 |
|
588 |
|
589 |
|
590 |
|
591 | function createCommit(message) {
|
592 |
|
593 | child_process_1.execSync('git add -A', { encoding: 'utf8', stdio: 'pipe' });
|
594 |
|
595 | child_process_1.execSync('git commit --no-verify -F -', { encoding: 'utf8', stdio: 'pipe', input: message });
|
596 | }
|
597 |
|
598 |
|
599 |
|
600 | function findCurrentGitSha() {
|
601 | try {
|
602 | const hash = child_process_1.execSync('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' });
|
603 | return hash.trim();
|
604 | }
|
605 | catch (_a) {
|
606 | return null;
|
607 | }
|
608 | }
|
609 | function getShortHash(commitHash) {
|
610 | return commitHash.slice(0, 9);
|
611 | }
|
612 | function coerceVersionNumber(version) {
|
613 | if (!version) {
|
614 | return null;
|
615 | }
|
616 | if (!version.match(/^\d{1,30}\.\d{1,30}\.\d{1,30}/)) {
|
617 | const match = version.match(/^\d{1,30}(\.\d{1,30})*/);
|
618 | if (!match) {
|
619 | return null;
|
620 | }
|
621 | if (!match[1]) {
|
622 | version = version.substr(0, match[0].length) + '.0.0' + version.substr(match[0].length);
|
623 | }
|
624 | else if (!match[2]) {
|
625 | version = version.substr(0, match[0].length) + '.0' + version.substr(match[0].length);
|
626 | }
|
627 | else {
|
628 | return null;
|
629 | }
|
630 | }
|
631 | return semver.valid(version);
|
632 | }
|