@ckeditor/ckeditor5-dev-release-tools 38.0.0 → 38.0.2

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.
@@ -24,11 +24,12 @@ const { glob } = require( 'glob' );
24
24
  * @param {Object} options
25
25
  * @param {String} options.packagesDirectory Relative path to a location of packages to be cleaned up.
26
26
  * @param {Array.<String>} [options.packageJsonFieldsToRemove] Fields to remove from `package.json`. If not set, a predefined list is used.
27
+ * @param {Boolean} [options.preservePostInstallHook] Whether to preserve the postinstall hook in `package.json`.
27
28
  * @param {String} [options.cwd] Current working directory from which all paths will be resolved.
28
29
  * @returns {Promise}
29
30
  */
30
31
  module.exports = async function cleanUpPackages( options ) {
31
- const { packagesDirectory, packageJsonFieldsToRemove, cwd } = parseOptions( options );
32
+ const { packagesDirectory, packageJsonFieldsToRemove, preservePostInstallHook, cwd } = parseOptions( options );
32
33
 
33
34
  const packageJsonPaths = await glob( '*/package.json', {
34
35
  cwd: upath.join( cwd, packagesDirectory ),
@@ -41,7 +42,7 @@ module.exports = async function cleanUpPackages( options ) {
41
42
  const packageJson = await fs.readJson( packageJsonPath );
42
43
 
43
44
  await cleanUpPackageDirectory( packageJson, packagePath );
44
- cleanUpPackageJson( packageJson, packageJsonFieldsToRemove );
45
+ cleanUpPackageJson( packageJson, packageJsonFieldsToRemove, preservePostInstallHook );
45
46
 
46
47
  await fs.writeJson( packageJsonPath, packageJson, { spaces: 2 } );
47
48
  }
@@ -53,6 +54,7 @@ module.exports = async function cleanUpPackages( options ) {
53
54
  * @param {Object} options
54
55
  * @param {String} options.packagesDirectory
55
56
  * @param {Array.<String>} [options.packageJsonFieldsToRemove=['devDependencies','depcheckIgnore','scripts','private']]
57
+ * @param {Boolean} [options.preservePostInstallHook]
56
58
  * @param {String} [options.cwd=process.cwd()]
57
59
  * @returns {Object}
58
60
  */
@@ -60,12 +62,14 @@ function parseOptions( options ) {
60
62
  const {
61
63
  packagesDirectory,
62
64
  packageJsonFieldsToRemove = [ 'devDependencies', 'depcheckIgnore', 'scripts', 'private' ],
65
+ preservePostInstallHook = false,
63
66
  cwd = process.cwd()
64
67
  } = options;
65
68
 
66
69
  return {
67
70
  packagesDirectory: upath.normalizeTrim( packagesDirectory ),
68
71
  packageJsonFieldsToRemove,
72
+ preservePostInstallHook,
69
73
  cwd: upath.normalizeTrim( cwd )
70
74
  };
71
75
  }
@@ -151,10 +155,17 @@ function getIgnoredFilePatterns( packageJson ) {
151
155
  *
152
156
  * @param {Object} packageJson
153
157
  * @param {Array.<String>} packageJsonFieldsToRemove
158
+ * @param {Boolean} preservePostInstallHook
154
159
  */
155
- function cleanUpPackageJson( packageJson, packageJsonFieldsToRemove ) {
160
+ function cleanUpPackageJson( packageJson, packageJsonFieldsToRemove, preservePostInstallHook ) {
156
161
  for ( const key of Object.keys( packageJson ) ) {
157
- if ( packageJsonFieldsToRemove.includes( key ) ) {
162
+ if ( !packageJsonFieldsToRemove.includes( key ) ) {
163
+ continue;
164
+ }
165
+
166
+ if ( key === 'scripts' && preservePostInstallHook && packageJson.scripts.postinstall ) {
167
+ packageJson.scripts = { 'postinstall': packageJson.scripts.postinstall };
168
+ } else {
158
169
  delete packageJson[ key ];
159
170
  }
160
171
  }
@@ -49,10 +49,6 @@ const noteInfo = `[ℹ️](${ VERSIONING_POLICY_URL }#major-and-minor-breaking-c
49
49
  *
50
50
  * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect.
51
51
  *
52
- * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights.
53
- *
54
- * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features.
55
- *
56
52
  * @param {String} [options.releaseBranch='master'] A name of the branch that should be used for releasing packages.
57
53
  *
58
54
  * @param {Array.<ExternalRepository>} [options.externalRepositories=[]] An array of object with additional repositories
@@ -386,10 +382,8 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
386
382
  commit: 'commit',
387
383
  repoUrl: getRepositoryUrl( options.cwd ),
388
384
  currentTag: 'v' + version,
389
- previousTag: 'v' + pkgJson.version,
385
+ previousTag: options.from ? options.from : 'v' + pkgJson.version,
390
386
  isPatch: semver.diff( version, pkgJson.version ) === 'patch',
391
- highlightsPlaceholder: options.highlightsPlaceholder || false,
392
- collaborationFeatures: options.collaborationFeatures || false,
393
387
  skipCommitsLink: Boolean( options.skipLinks ),
394
388
  skipCompareLink: Boolean( options.skipLinks )
395
389
  };
@@ -503,6 +497,8 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
503
497
  } );
504
498
  }
505
499
 
500
+ // When the `--from` flag is specified, we want to use its value as the "current version".
501
+ const currentVersion = options.from ? options.from.replace( /^v/, '' ) : null;
506
502
  const newPackages = getNewPackages( dependencies );
507
503
  const majorBreakingChangesPackages = getPackagesMatchedToScopesFromNotes( dependencies, 'MAJOR BREAKING CHANGES' );
508
504
  const minorBreakingChangesPackages = getPackagesMatchedToScopesFromNotes( dependencies, 'MINOR BREAKING CHANGES' );
@@ -527,7 +523,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
527
523
  entries.push( '\nMajor releases (contain major breaking changes):\n' );
528
524
 
529
525
  for ( const [ packageName, version ] of [ ...majorBreakingChangesPackages ].sort( sortByPackageName ) ) {
530
- entries.push( formatChangelogEntry( packageName, version.next, version.current ) );
526
+ entries.push( formatChangelogEntry( packageName, version.next, currentVersion || version.current ) );
531
527
  }
532
528
  }
533
529
 
@@ -535,7 +531,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
535
531
  entries.push( '\nMinor releases (contain minor breaking changes):\n' );
536
532
 
537
533
  for ( const [ packageName, version ] of [ ...minorBreakingChangesPackages ].sort( sortByPackageName ) ) {
538
- entries.push( formatChangelogEntry( packageName, version.next, version.current ) );
534
+ entries.push( formatChangelogEntry( packageName, version.next, currentVersion || version.current ) );
539
535
  }
540
536
  }
541
537
 
@@ -543,7 +539,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
543
539
  entries.push( '\nReleases containing new features:\n' );
544
540
 
545
541
  for ( const [ packageName, version ] of [ ...newFeaturesPackages ].sort( sortByPackageName ) ) {
546
- entries.push( formatChangelogEntry( packageName, version.next, version.current ) );
542
+ entries.push( formatChangelogEntry( packageName, version.next, currentVersion || version.current ) );
547
543
  }
548
544
  }
549
545
 
@@ -551,7 +547,7 @@ module.exports = async function generateChangelogForMonoRepository( options ) {
551
547
  entries.push( '\nOther releases:\n' );
552
548
 
553
549
  for ( const [ packageName, version ] of [ ...dependencies ].sort( sortByPackageName ) ) {
554
- entries.push( formatChangelogEntry( packageName, version.next, version.current ) );
550
+ entries.push( formatChangelogEntry( packageName, version.next, currentVersion || version.current ) );
555
551
  }
556
552
  }
557
553
 
@@ -33,10 +33,6 @@ const SKIP_GENERATE_CHANGELOG = 'Typed "skip" as a new version. Aborting.';
33
33
  *
34
34
  * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect.
35
35
  *
36
- * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights.
37
- *
38
- * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features.
39
- *
40
36
  * @param {String} [options.releaseBranch='master'] A name of the branch that should be used for releasing packages.
41
37
  *
42
38
  * @returns {Promise}
@@ -97,18 +93,14 @@ module.exports = async function generateChangelogForSinglePackage( options = {}
97
93
 
98
94
  logProcess( 'Generating the changelog...' );
99
95
 
100
- const previousTag = commitOptions.from ? 'v' + pkgJson.version : null;
101
-
102
96
  const writerContext = {
103
97
  version,
104
98
  commit: 'commit',
105
99
  repoUrl: getRepositoryUrl(),
106
100
  currentTag: 'v' + version,
107
- previousTag,
101
+ previousTag: options.from ? options.from : 'v' + pkgJson.version,
108
102
  isPatch: semver.diff( version, pkgJson.version ) === 'patch',
109
103
  isInternalRelease,
110
- highlightsPlaceholder: Boolean( options.highlightsPlaceholder ),
111
- collaborationFeatures: Boolean( options.collaborationFeatures ),
112
104
  skipCommitsLink: Boolean( options.skipLinks ),
113
105
  skipCompareLink: Boolean( options.skipLinks )
114
106
  };
@@ -95,7 +95,8 @@ function validateRootPackage( packageJson ) {
95
95
  * @returns {Promise}
96
96
  */
97
97
  async function processRootPackage( { cwd, rootPackageJson, outputDirectoryPath } ) {
98
- const rootPackageOutputPath = upath.join( outputDirectoryPath, rootPackageJson.name );
98
+ const rootPackageDirName = rootPackageJson.name.replace( /^@.*\//, '' );
99
+ const rootPackageOutputPath = upath.join( outputDirectoryPath, rootPackageDirName );
99
100
  const pkgJsonOutputPath = upath.join( rootPackageOutputPath, 'package.json' );
100
101
 
101
102
  await fs.ensureDir( rootPackageOutputPath );
@@ -11,7 +11,8 @@ const assertNpmAuthorization = require( '../utils/assertnpmauthorization' );
11
11
  const assertPackages = require( '../utils/assertpackages' );
12
12
  const assertNpmTag = require( '../utils/assertnpmtag' );
13
13
  const assertFilesToPublish = require( '../utils/assertfilestopublish' );
14
- const publishPackagesOnNpm = require( '../utils/publishpackagesonnpm' );
14
+ const executeInParallel = require( '../utils/executeinparallel' );
15
+ const publishPackageOnNpmCallback = require( '../utils/publishpackageonnpmcallback' );
15
16
 
16
17
  /**
17
18
  * The purpose of the script is to validate the packages prepared for the release and then release them on npm.
@@ -29,6 +30,7 @@ const publishPackagesOnNpm = require( '../utils/publishpackagesonnpm' );
29
30
  * @param {String} options.packagesDirectory Relative path to a location of packages to release.
30
31
  * @param {String} options.npmOwner The account name on npm, which should be used to publish the packages.
31
32
  * @param {ListrTaskObject} options.listrTask An instance of `ListrTask`.
33
+ * @param {AbortSignal|null} [options.signal=null] Signal to abort the asynchronous process.
32
34
  * @param {String} [options.npmTag='staging'] The npm distribution tag.
33
35
  * @param {Object.<String, Array.<String>>|null} [options.optionalEntries=null] Specifies which entries from the `files` field in the
34
36
  * `package.json` are optional. The key is a package name, and its value is an array of optional entries from the `files` field, for which
@@ -37,6 +39,7 @@ const publishPackagesOnNpm = require( '../utils/publishpackagesonnpm' );
37
39
  * @param {String} [options.confirmationCallback=null] An callback whose response decides to continue the publishing packages. Synchronous
38
40
  * and asynchronous callbacks are supported.
39
41
  * @param {String} [options.cwd=process.cwd()] Current working directory from which all paths will be resolved.
42
+ * @param {Number} [options.concurrency=4] Number of CPUs that will execute the task.
40
43
  * @returns {Promise}
41
44
  */
42
45
  module.exports = async function publishPackages( options ) {
@@ -44,10 +47,12 @@ module.exports = async function publishPackages( options ) {
44
47
  packagesDirectory,
45
48
  npmOwner,
46
49
  listrTask,
50
+ signal = null,
47
51
  npmTag = 'staging',
48
52
  optionalEntries = null,
49
53
  confirmationCallback = null,
50
- cwd = process.cwd()
54
+ cwd = process.cwd(),
55
+ concurrency = 4
51
56
  } = options;
52
57
 
53
58
  await assertNpmAuthorization( npmOwner );
@@ -64,6 +69,15 @@ module.exports = async function publishPackages( options ) {
64
69
  const shouldPublishPackages = confirmationCallback ? await confirmationCallback() : true;
65
70
 
66
71
  if ( shouldPublishPackages ) {
67
- await publishPackagesOnNpm( packagePaths, npmTag, listrTask );
72
+ await executeInParallel( {
73
+ packagesDirectory,
74
+ listrTask,
75
+ taskToExecute: publishPackageOnNpmCallback,
76
+ taskOptions: {
77
+ npmTag
78
+ },
79
+ signal,
80
+ concurrency
81
+ } );
68
82
  }
69
83
  };
@@ -5,18 +5,6 @@ Internal changes only (updated dependencies, documentation, etc.).
5
5
 
6
6
 
7
7
  {{else}}
8
- {{#if highlightsPlaceholder}}
9
- ### Release highlights
10
-
11
- <!-- TODO: Add a link to the blog post. -->
12
-
13
- {{/if}}
14
- {{#if collaborationFeatures}}
15
- ### Collaboration features
16
-
17
- The CKEditor 5 Collaboration features changelog can be found here: https://ckeditor.com/collaboration/changelog.
18
-
19
- {{/if}}
20
8
  {{> footer}}
21
9
  {{#each commitGroups}}
22
10
  ### {{title}}
@@ -0,0 +1,47 @@
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
+ /* eslint-env node */
7
+
8
+ 'use strict';
9
+
10
+ /**
11
+ * Creates an AbortController instance and registers the listener function on SIGINT event that aborts the asynchronous process.
12
+ *
13
+ * @returns {AbortController}
14
+ */
15
+ function registerAbortController() {
16
+ const abortController = new AbortController();
17
+
18
+ const listener = () => {
19
+ abortController.abort( 'SIGINT' );
20
+ };
21
+
22
+ abortController._listener = listener;
23
+
24
+ // Add the listener function to the beginning of the listeners array for the SIGINT event. Listr2 has own SIGINT listener that
25
+ // terminates the process, so in order to abort our asynchronous workers, our listener must be executed first.
26
+ process.prependOnceListener( 'SIGINT', abortController._listener );
27
+
28
+ return abortController;
29
+ }
30
+
31
+ /**
32
+ * Deregisters the previously registered listener function on SIGINT event from the given AbortController instance.
33
+ *
34
+ * @param {AbortController} abortController
35
+ */
36
+ function deregisterAbortController( abortController ) {
37
+ if ( !abortController || !abortController._listener ) {
38
+ return;
39
+ }
40
+
41
+ process.removeListener( 'SIGINT', abortController._listener );
42
+ }
43
+
44
+ module.exports = {
45
+ registerAbortController,
46
+ deregisterAbortController
47
+ };
@@ -12,6 +12,7 @@ const upath = require( 'upath' );
12
12
  const fs = require( 'fs/promises' );
13
13
  const { Worker } = require( 'worker_threads' );
14
14
  const { glob } = require( 'glob' );
15
+ const { registerAbortController, deregisterAbortController } = require( './abortcontroller' );
15
16
 
16
17
  const WORKER_SCRIPT = upath.join( __dirname, 'parallelworker.js' );
17
18
 
@@ -27,9 +28,10 @@ const WORKER_SCRIPT = upath.join( __dirname, 'parallelworker.js' );
27
28
  * @param {String} options.packagesDirectory Relative path to a location of packages to execute a task.
28
29
  * @param {Function} options.taskToExecute A callback that is executed on all found packages.
29
30
  * It receives an absolute path to a package as an argument. It can be synchronous or may return a promise.
30
- * @param {AbortSignal} options.signal Signal to abort the asynchronous process.
31
31
  * @param {ListrTaskObject} options.listrTask An instance of `ListrTask`.
32
- * @param {Function} [options.packagesDirectoryFilter] A function that is executed for each found package directory to filter out those
32
+ * @param {AbortSignal|null} [options.signal=null] Signal to abort the asynchronous process. If not set, default AbortController is created.
33
+ * @param {Object} [options.taskOptions=null] Optional data required by the task.
34
+ * @param {Function} [options.packagesDirectoryFilter=null] A function that is executed for each found package directory to filter out those
33
35
  * that do not require executing a task. It should return a truthy value to keep the package and a falsy value to skip the package from
34
36
  * processing.
35
37
  * @param {String} [options.cwd=process.cwd()] Current working directory from which all paths will be resolved.
@@ -39,19 +41,20 @@ const WORKER_SCRIPT = upath.join( __dirname, 'parallelworker.js' );
39
41
  module.exports = async function executeInParallel( options ) {
40
42
  const {
41
43
  packagesDirectory,
42
- signal,
43
44
  taskToExecute,
44
45
  listrTask,
46
+ signal = null,
47
+ taskOptions = null,
45
48
  packagesDirectoryFilter = null,
46
49
  cwd = process.cwd(),
47
50
  concurrency = require( 'os' ).cpus().length / 2
48
51
  } = options;
49
52
 
50
53
  const normalizedCwd = upath.toUnix( cwd );
51
- const packages = await glob( `${ packagesDirectory }/*/`, {
54
+ const packages = ( await glob( `${ packagesDirectory }/*/`, {
52
55
  cwd: normalizedCwd,
53
56
  absolute: true
54
- } );
57
+ } ) ).map( upath.normalize );
55
58
 
56
59
  const packagesToProcess = packagesDirectoryFilter ?
57
60
  packages.filter( packagesDirectoryFilter ) :
@@ -64,11 +67,17 @@ module.exports = async function executeInParallel( options ) {
64
67
 
65
68
  const onPackageDone = progressFactory( listrTask, packagesToProcess.length );
66
69
 
70
+ let defaultAbortController;
71
+
72
+ if ( !signal ) {
73
+ defaultAbortController = registerAbortController();
74
+ }
75
+
67
76
  const workers = packagesInThreads.map( packages => {
68
77
  return createWorker( {
69
- signal,
78
+ signal: signal || defaultAbortController.signal,
70
79
  onPackageDone,
71
- workerData: { packages, callbackModule }
80
+ workerData: { packages, callbackModule, taskOptions }
72
81
  } );
73
82
  } );
74
83
 
@@ -83,6 +92,10 @@ module.exports = async function executeInParallel( options ) {
83
92
  } )
84
93
  .finally( async () => {
85
94
  await fs.unlink( callbackModule );
95
+
96
+ if ( defaultAbortController ) {
97
+ deregisterAbortController( defaultAbortController );
98
+ }
86
99
  } );
87
100
  };
88
101
 
@@ -22,8 +22,6 @@ const UPDATED_TRANSLATION_COMMIT = '* Updated translations.';
22
22
  * @param {String} context.currentTag A tag for the current version.
23
23
  * @param {String} context.commit Commit keyword in the URL.
24
24
  * @param {String} [context.previousTag] A tag for the previous version.
25
- * @param {Boolean} [options.highlightsPlaceholder=false] Whether to add a note about release highlights.
26
- * @param {Boolean} [options.collaborationFeatures=false] Whether to add a note about collaboration features.
27
25
  * @param {Boolean} [context.skipCommitsLink=false] Whether to skip adding links to commit.
28
26
  * @param {Boolean} [context.skipCompareLink=false] Whether to remove the compare URL in the header.
29
27
  *
@@ -17,7 +17,7 @@
17
17
  const callback = require( workerData.callbackModule );
18
18
 
19
19
  for ( const packagePath of workerData.packages ) {
20
- await callback( packagePath );
20
+ await callback( packagePath, workerData.taskOptions );
21
21
 
22
22
  // To increase the status log.
23
23
  parentPort.postMessage( 'done:package' );
@@ -0,0 +1,31 @@
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
+ /* eslint-env node */
7
+
8
+ 'use strict';
9
+
10
+ /**
11
+ * Calls the npm command to publish the package. When a package is successfully published, it is removed from the filesystem.
12
+ *
13
+ * @param {String} packagePath
14
+ * @param {Object} taskOptions
15
+ * @param {String} taskOptions.npmTag
16
+ * @returns {Promise}
17
+ */
18
+ module.exports = async function publishPackageOnNpmCallback( packagePath, taskOptions ) {
19
+ const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
20
+ const upath = require( 'upath' );
21
+ const fs = require( 'fs-extra' );
22
+
23
+ await tools.shExec( `npm publish --access=public --tag ${ taskOptions.npmTag }`, { cwd: packagePath, async: true, verbosity: 'error' } )
24
+ .catch( () => {
25
+ const packageName = upath.basename( packagePath );
26
+
27
+ throw new Error( `Unable to publish "${ packageName }" package.` );
28
+ } );
29
+
30
+ await fs.remove( packagePath );
31
+ };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-dev-release-tools",
3
- "version": "38.0.0",
3
+ "version": "38.0.2",
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.0.0",
8
+ "@ckeditor/ckeditor5-dev-utils": "^38.0.2",
9
9
  "@octokit/rest": "^17.9.2",
10
10
  "chalk": "^4.0.0",
11
11
  "cli-table": "^0.3.1",
@@ -1,35 +0,0 @@
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 fs = require( 'fs-extra' );
9
- const upath = require( 'upath' );
10
- const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
11
-
12
- /**
13
- * Calls the npm command to publish all packages. When a package is successfully published, it is removed from the filesystem.
14
- *
15
- * @param {Array.<String>} packagePaths
16
- * @param {String} npmTag
17
- * @param {ListrTaskObject} listrTask
18
- * @returns {Promise}
19
- */
20
- module.exports = async function publishPackagesOnNpm( packagePaths, npmTag, listrTask ) {
21
- let index = 0;
22
-
23
- for ( const packagePath of packagePaths ) {
24
- listrTask.output = `Status: ${ ++index }/${ packagePaths.length }. Processing the "${ upath.basename( packagePath ) }" directory.`;
25
-
26
- await tools.shExec( `npm publish --access=public --tag ${ npmTag }`, { cwd: packagePath, async: true, verbosity: 'error' } )
27
- .catch( () => {
28
- const packageName = upath.basename( packagePath );
29
-
30
- throw new Error( `Unable to publish "${ packageName }" package.` );
31
- } );
32
-
33
- await fs.remove( packagePath );
34
- }
35
- };