@ckeditor/ckeditor5-dev-release-tools 38.1.4 → 38.2.0

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/lib/index.js CHANGED
@@ -20,6 +20,7 @@ const { getLastFromChangelog, getLastNightly, getNextNightly, getCurrent, getLas
20
20
  const { getChangesForVersion, getChangelog, saveChangelog } = require( './utils/changelog' );
21
21
  const executeInParallel = require( './utils/executeinparallel' );
22
22
  const validateRepositoryToRelease = require( './utils/validaterepositorytorelease' );
23
+ const checkVersionAvailability = require( './utils/checkversionavailability' );
23
24
 
24
25
  module.exports = {
25
26
  generateChangelogForSinglePackage,
@@ -42,5 +43,6 @@ module.exports = {
42
43
  getChangesForVersion,
43
44
  getChangelog,
44
45
  saveChangelog,
45
- validateRepositoryToRelease
46
+ validateRepositoryToRelease,
47
+ checkVersionAvailability
46
48
  };
@@ -54,12 +54,17 @@ const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-c
54
54
  * @param {Array.<ExternalRepository>} [options.externalRepositories=[]] An array of object with additional repositories
55
55
  * that the function takes into consideration while gathering commits. It assumes that those directories are also mono repositories.
56
56
  *
57
- * @returns {Promise}
57
+ * @param {Boolean} [options.skipFileSave=false] Whether to resolve the changes instead of saving it to a file.
58
+ *
59
+ * @param {String|null} [options.nextVersion=null] Next version to use. If not provided, a user needs to provide via CLI.
60
+ *
61
+ * @returns {Promise.<undefined|String>}
58
62
  */
59
63
  module.exports = async function generateChangelogForMonoRepository( options ) {
60
64
  const log = logger();
61
65
  const cwd = process.cwd();
62
- const pkgJson = getPackageJson( options.cwd );
66
+ const rootPkgJson = getPackageJson( options.cwd );
67
+ const skipFileSave = options.skipFileSave || false;
63
68
 
64
69
  logProcess( 'Collecting paths to packages...' );
65
70
 
@@ -71,16 +76,23 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
71
76
  externalRepositories: options.externalRepositories || []
72
77
  } );
73
78
 
79
+ const commitOptions = {
80
+ cwd: options.cwd,
81
+ from: options.from ? options.from : 'v' + rootPkgJson.version,
82
+ releaseBranch: options.releaseBranch || 'master',
83
+ externalRepositories: options.externalRepositories || []
84
+ };
85
+
74
86
  logProcess( 'Collecting all commits since the last release...' );
75
87
 
76
88
  // Collection of all entries (real commits + additional "fake" commits extracted from descriptions).
77
- let allCommits;
89
+ const allCommits = await gatherAllCommits( commitOptions );
78
90
 
79
91
  // Collection of public entries that will be inserted in the changelog.
80
92
  let publicCommits;
81
93
 
82
- // The next version for the upcoming release.
83
- let nextVersion = null;
94
+ // The next version for the upcoming release. If not specified, a user has to provide via CLI.
95
+ let nextVersion = options.nextVersion || null;
84
96
 
85
97
  // A map contains packages and their new versions.
86
98
  const packagesVersion = new Map();
@@ -91,44 +103,52 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
91
103
  // A map contains packages and their paths (where they are located)
92
104
  const packagesPaths = new Map();
93
105
 
94
- const commitOptions = {
95
- cwd: options.cwd,
96
- from: options.from ? options.from : 'v' + pkgJson.version,
97
- releaseBranch: options.releaseBranch || 'master',
98
- externalRepositories: options.externalRepositories || []
99
- };
106
+ logInfo( `Found ${ allCommits.length } entries to parse.`, { indentLevel: 1, startWithNewLine: true } );
100
107
 
101
- return gatherAllCommits( commitOptions )
102
- .then( commits => {
103
- allCommits = commits;
108
+ // If the next version is specified by the integrator, setup internal values used when preparing
109
+ // the "Releases packages" section.
110
+ if ( nextVersion ) {
111
+ packagesVersion.set( rootPkgJson.name, nextVersion );
104
112
 
105
- logInfo( `Found ${ commits.length } entries to parse.`, { indentLevel: 1, startWithNewLine: true } );
106
- } )
107
- .then( () => typeNewVersionForAllPackages() )
108
- .then( () => generateChangelogFromCommits() )
109
- .then( changesFromCommits => saveChangelog( changesFromCommits ) )
110
- .then( () => {
111
- logProcess( 'Summary' );
113
+ for ( const packagePath of pathsCollection.matched ) {
114
+ const packageJson = getPackageJson( packagePath );
112
115
 
113
- displaySkippedPackages( new Set( [
114
- ...pathsCollection.skipped
115
- ].sort() ) );
116
+ currentPackagesVersion.set( packageJson.name, packageJson.version );
117
+ packagesPaths.set( packageJson.name, packagePath );
118
+ packagesVersion.set( packageJson.name, nextVersion );
119
+ }
120
+ } else {
121
+ await typeNewVersionForAllPackages();
122
+ }
116
123
 
117
- // Make a commit from the repository where we started.
118
- process.chdir( options.cwd );
119
- tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } );
120
- tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } );
121
-
122
- logInfo(
123
- `Changelog for "${ chalk.underline( pkgJson.name ) }" (v${ packagesVersion.get( pkgJson.name ) }) has been generated.`,
124
- { indentLevel: 1 }
125
- );
126
-
127
- process.chdir( cwd );
128
- } )
129
- .catch( err => {
130
- console.log( err );
131
- } );
124
+ if ( !skipFileSave ) {
125
+ await saveChangelog();
126
+
127
+ // Make a commit from the repository where we started.
128
+ process.chdir( options.cwd );
129
+ tools.shExec( `git add ${ changelogUtils.changelogFile }`, { verbosity: 'error' } );
130
+ tools.shExec( 'git commit -m "Docs: Changelog. [skip ci]"', { verbosity: 'error' } );
131
+ logInfo( 'Committed.', { indentLevel: 1 } );
132
+ }
133
+
134
+ process.chdir( cwd );
135
+
136
+ logProcess( 'Summary' );
137
+
138
+ displaySkippedPackages( new Set( [
139
+ ...pathsCollection.skipped
140
+ ].sort() ) );
141
+
142
+ logInfo(
143
+ `Changelog for "${ chalk.underline( rootPkgJson.name ) }" (v${ packagesVersion.get( rootPkgJson.name ) }) has been generated.`,
144
+ { indentLevel: 1 }
145
+ );
146
+
147
+ if ( skipFileSave ) {
148
+ return getChangelogForNextVersion();
149
+ }
150
+
151
+ return Promise.resolve();
132
152
 
133
153
  /**
134
154
  * Returns collections with packages found in the `options.cwd` directory and the external repositories.
@@ -191,6 +211,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
191
211
  * @returns {Promise.<Array.<Commit>>}
192
212
  */
193
213
  function gatherAllCommits( options ) {
214
+ process.chdir( options.cwd );
194
215
  logInfo( `Processing "${ options.cwd }"...`, { indentLevel: 1 } );
195
216
 
196
217
  const transformCommit = transformCommitFactory( {
@@ -375,15 +396,15 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
375
396
  function generateChangelogFromCommits() {
376
397
  logProcess( 'Generating the changelog...' );
377
398
 
378
- const version = packagesVersion.get( pkgJson.name );
399
+ const version = packagesVersion.get( rootPkgJson.name );
379
400
 
380
401
  const writerContext = {
381
402
  version,
382
403
  commit: 'commit',
383
404
  repoUrl: getRepositoryUrl( options.cwd ),
384
405
  currentTag: 'v' + version,
385
- previousTag: options.from ? options.from : 'v' + pkgJson.version,
386
- isPatch: semver.diff( version, pkgJson.version ) === 'patch',
406
+ previousTag: options.from ? options.from : 'v' + rootPkgJson.version,
407
+ isPatch: semver.diff( version, rootPkgJson.version ) === 'patch',
387
408
  skipCommitsLink: Boolean( options.skipLinks ),
388
409
  skipCompareLink: Boolean( options.skipLinks )
389
410
  };
@@ -434,13 +455,25 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
434
455
  }
435
456
  }
436
457
 
458
+ async function getChangelogForNextVersion() {
459
+ const changesFromCommits = await generateChangelogFromCommits();
460
+ const dependenciesSummary = generateSummaryOfChangesInPackages();
461
+
462
+ return [
463
+ changelogUtils.changelogHeader,
464
+ changesFromCommits.trim(),
465
+ '\n\n',
466
+ dependenciesSummary
467
+ ].join( '' );
468
+ }
469
+
437
470
  /**
438
471
  * Combines the generated changes based on commits and summary of version changes in packages.
439
472
  * Appends those changes at the beginning of the changelog file.
440
473
  *
441
474
  * @param {String} changesFromCommits Generated entries based on commits.
442
475
  */
443
- function saveChangelog( changesFromCommits ) {
476
+ async function saveChangelog() {
444
477
  logProcess( 'Saving changelog...' );
445
478
 
446
479
  if ( !fs.existsSync( changelogUtils.changelogFile ) ) {
@@ -451,20 +484,15 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
451
484
 
452
485
  logInfo( 'Preparing a summary of version changes in packages.', { indentLevel: 1 } );
453
486
 
454
- const dependenciesSummary = generateSummaryOfChangesInPackages();
455
-
456
487
  let currentChangelog = changelogUtils.getChangelog();
457
488
 
489
+ const nextVersionChangelog = await getChangelogForNextVersion();
490
+
458
491
  // Remove header from current changelog.
459
492
  currentChangelog = currentChangelog.replace( changelogUtils.changelogHeader, '' ).trim();
460
493
 
461
494
  // Concat header, new entries and old changelog to single string.
462
- let newChangelog = changelogUtils.changelogHeader +
463
- changesFromCommits.trim() +
464
- '\n\n' +
465
- dependenciesSummary +
466
- '\n\n\n' +
467
- currentChangelog;
495
+ let newChangelog = nextVersionChangelog + '\n\n\n' + currentChangelog;
468
496
 
469
497
  newChangelog = newChangelog.trim() + '\n';
470
498
 
@@ -487,7 +515,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
487
515
 
488
516
  for ( const [ packageName, nextVersion ] of packagesVersion ) {
489
517
  // Skip the package hosted in the main repository.
490
- if ( packageName === pkgJson.name ) {
518
+ if ( packageName === rootPkgJson.name ) {
491
519
  continue;
492
520
  }
493
521
 
@@ -642,7 +670,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
642
670
  * @returns {String}
643
671
  */
644
672
  function formatChangelogEntry( packageName, nextVersion, currentVersion = null ) {
645
- const npmUrl = `https://www.npmjs.com/package/${ packageName }`;
673
+ const npmUrl = `https://www.npmjs.com/package/${ packageName }/v/${ nextVersion }`;
646
674
 
647
675
  if ( currentVersion ) {
648
676
  return `* [${ packageName }](${ npmUrl }): v${ currentVersion } => v${ nextVersion }`;
@@ -661,7 +689,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
661
689
  return compareFunc( item => {
662
690
  if ( Array.isArray( item[ scopeField ] ) ) {
663
691
  // A hack that allows moving all scoped commits from the main repository/package at the beginning of the list.
664
- if ( item[ scopeField ][ 0 ] === pkgJson.name ) {
692
+ if ( item[ scopeField ][ 0 ] === rootPkgJson.name ) {
665
693
  return 'a'.repeat( 15 );
666
694
  }
667
695
 
@@ -9,7 +9,7 @@ const { glob } = require( 'glob' );
9
9
  const fs = require( 'fs-extra' );
10
10
  const semver = require( 'semver' );
11
11
  const { normalizeTrim, toUnix, dirname, join } = require( 'upath' );
12
- const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
12
+ const checkVersionAvailability = require( '../utils/checkversionavailability' );
13
13
 
14
14
  /**
15
15
  * The purpose of the script is to update the version of a root package found in the current working
@@ -38,10 +38,18 @@ module.exports = async function updateVersions( { packagesDirectory, version, cw
38
38
  const randomPackagePath = getRandomPackagePath( pkgJsonPaths, normalizedPackagesDir );
39
39
 
40
40
  const rootPackageJson = join( normalizedCwd, 'package.json' );
41
+ const rootPackageVersion = ( await fs.readJson( rootPackageJson ) ).version;
42
+
41
43
  const randomPackageJson = join( randomPackagePath, 'package.json' );
44
+ const randomPackageName = ( await fs.readJson( randomPackageJson ) ).name;
45
+
46
+ checkIfVersionIsValid( version, rootPackageVersion );
42
47
 
43
- checkIfVersionIsValid( version, ( await fs.readJson( rootPackageJson ) ).version );
44
- await checkVersionAvailability( version, ( await fs.readJson( randomPackageJson ) ).name );
48
+ const isVersionAvailable = await checkVersionAvailability( version, randomPackageName );
49
+
50
+ if ( !isVersionAvailable ) {
51
+ throw new Error( `The "${ randomPackageName }@${ version }" already exists in the npm registry.` );
52
+ }
45
53
 
46
54
  for ( const pkgJsonPath of pkgJsonPaths ) {
47
55
  const pkgJson = await fs.readJson( pkgJsonPath );
@@ -96,22 +104,3 @@ function checkIfVersionIsValid( newVersion, currentVersion ) {
96
104
  throw new Error( `Provided version ${ newVersion } must be greater than ${ currentVersion } or match pattern 0.0.0-nightly.` );
97
105
  }
98
106
  }
99
-
100
- /**
101
- * Checks if the provided version is not used in npm and there will be no errors when calling publish.
102
- *
103
- * @param {String} version
104
- * @param {String} packageName
105
- * @returns {Promise}
106
- */
107
- async function checkVersionAvailability( version, packageName ) {
108
- return tools.shExec( `npm show ${ packageName }@${ version } version`, { verbosity: 'silent', async: true } )
109
- .then( () => {
110
- throw new Error( `Provided version ${ version } is already used in npm by ${ packageName }.` );
111
- } )
112
- .catch( err => {
113
- if ( !err.toString().includes( 'is not in this registry' ) ) {
114
- throw err;
115
- }
116
- } );
117
- }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
9
+
10
+ /**
11
+ * Checks if the provided version for the package exists in the npm registry.
12
+ *
13
+ * Returns a promise that resolves to `true` if the provided version does not exist or resolves the promise to `false` otherwise.
14
+ * If the `npm show` command exits with an error, it is re-thrown.
15
+ *
16
+ * @param {String} version
17
+ * @param {String} packageName
18
+ * @returns {Promise}
19
+ */
20
+ module.exports = async function checkVersionAvailability( version, packageName ) {
21
+ return tools.shExec( `npm show ${ packageName }@${ version } version`, { verbosity: 'silent', async: true } )
22
+ .then( result => {
23
+ // Explicit check for npm < 8.13.0, which does not return anything (an empty result) and it exits with a zero status code when
24
+ // the version for the provided package does not exist in the npm registry.
25
+ if ( !result ) {
26
+ return true;
27
+ }
28
+
29
+ // Provided version exists in the npm registry.
30
+ return false;
31
+ } )
32
+ .catch( error => {
33
+ // All errors except the "E404" are re-thrown.
34
+ if ( !error.toString().includes( 'npm ERR! code E404' ) ) {
35
+ throw error;
36
+ }
37
+
38
+ // Npm >= 8.13.0 throws an "E404" error if a version does not exist.
39
+ // Npm < 8.13.0 should never reach this line.
40
+ return true;
41
+ } );
42
+ };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-dev-release-tools",
3
- "version": "38.1.4",
3
+ "version": "38.2.0",
4
4
  "description": "Tools used for releasing CKEditor 5 and related packages.",
5
5
  "keywords": [],
6
6
  "main": "lib/index.js",
7
7
  "dependencies": {
8
- "@ckeditor/ckeditor5-dev-utils": "^38.1.4",
8
+ "@ckeditor/ckeditor5-dev-utils": "^38.2.0",
9
9
  "@octokit/rest": "^19.0.0",
10
10
  "chalk": "^4.0.0",
11
11
  "cli-table": "^0.3.1",