@ckeditor/ckeditor5-dev-release-tools 44.0.0-alpha.5 → 44.1.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.
Files changed (48) hide show
  1. package/lib/index.js +1 -0
  2. package/lib/tasks/cleanuppackages.js +24 -28
  3. package/lib/tasks/commitandtag.js +16 -21
  4. package/lib/tasks/creategithubrelease.js +11 -23
  5. package/lib/tasks/generatechangelogformonorepository.js +62 -55
  6. package/lib/tasks/generatechangelogforsinglepackage.js +17 -14
  7. package/lib/tasks/preparerepository.js +19 -19
  8. package/lib/tasks/publishpackages.js +88 -31
  9. package/lib/tasks/push.js +4 -4
  10. package/lib/tasks/reassignnpmtags.js +8 -8
  11. package/lib/tasks/updatedependencies.js +23 -43
  12. package/lib/tasks/updateversions.js +22 -96
  13. package/lib/tasks/verifypackagespublishedcorrectly.js +18 -12
  14. package/lib/utils/assertfilestopublish.js +6 -6
  15. package/lib/utils/assertnpmauthorization.js +1 -1
  16. package/lib/utils/assertnpmtag.js +10 -24
  17. package/lib/utils/assertpackages.js +4 -4
  18. package/lib/utils/checkversionavailability.js +8 -24
  19. package/lib/utils/configurereleaseoptions.js +1 -1
  20. package/lib/utils/confirmincludingpackage.js +1 -1
  21. package/lib/utils/confirmnpmtag.js +3 -3
  22. package/lib/utils/displaycommits.js +4 -4
  23. package/lib/utils/executeinparallel.js +24 -29
  24. package/lib/utils/findpathstopackages.js +78 -0
  25. package/lib/utils/generatechangelog.js +23 -23
  26. package/lib/utils/getchangedfilesforcommit.js +2 -2
  27. package/lib/utils/getchangelog.js +2 -2
  28. package/lib/utils/getchangesforversion.js +3 -3
  29. package/lib/utils/getcommits.js +7 -6
  30. package/lib/utils/getformatteddate.js +1 -1
  31. package/lib/utils/getnewversiontype.js +1 -1
  32. package/lib/utils/getnpmtagfromversion.js +11 -2
  33. package/lib/utils/getpackagejson.js +2 -2
  34. package/lib/utils/getpackagespaths.js +9 -9
  35. package/lib/utils/getwriteroptions.js +1 -1
  36. package/lib/utils/isversionpublishablefortag.js +8 -10
  37. package/lib/utils/parallelworker.js +2 -2
  38. package/lib/utils/providenewversionformonorepository.js +28 -12
  39. package/lib/utils/providetoken.js +1 -1
  40. package/lib/utils/provideversion.js +41 -24
  41. package/lib/utils/publishpackageonnpmcallback.js +10 -20
  42. package/lib/utils/savechangelog.js +2 -2
  43. package/lib/utils/transformcommitfactory.js +27 -27
  44. package/lib/utils/transformcommitutils.js +13 -13
  45. package/lib/utils/truncatechangelog.js +2 -2
  46. package/lib/utils/validaterepositorytorelease.js +6 -6
  47. package/lib/utils/versions.js +17 -16
  48. package/package.json +3 -2
@@ -3,41 +3,25 @@
3
3
  * For licensing, see LICENSE.md.
4
4
  */
5
5
 
6
- import { tools } from '@ckeditor/ckeditor5-dev-utils';
7
- import shellEscape from 'shell-escape';
6
+ import pacote from 'pacote';
8
7
 
9
8
  /**
10
9
  * Checks if the provided version for the package exists in the npm registry.
11
10
  *
12
11
  * Returns a promise that resolves to `true` if the provided version does not exist or resolves the promise to `false` otherwise.
13
- * If the `npm show` command exits with an error, it is re-thrown.
14
12
  *
15
- * @param {String} version
16
- * @param {String} packageName
13
+ * @param {string} version
14
+ * @param {string} packageName
17
15
  * @returns {Promise}
18
16
  */
19
17
  export default async function checkVersionAvailability( version, packageName ) {
20
- const command = `npm show ${ shellEscape( [ packageName ] ) }@${ shellEscape( [ version ] ) } version`;
21
-
22
- return tools.shExec( command, { verbosity: 'silent', async: true } )
23
- .then( result => {
24
- // Explicit check for npm < 8.13.0, which does not return anything (an empty result) and it exits with a zero status code when
25
- // the version for the provided package does not exist in the npm registry.
26
- if ( !result ) {
27
- return true;
28
- }
29
-
30
- // Provided version exists in the npm registry.
18
+ return pacote.manifest( `${ packageName }@${ version }` )
19
+ .then( () => {
20
+ // If `pacote.manifest` resolves, a package with the given version exists.
31
21
  return false;
32
22
  } )
33
- .catch( error => {
34
- // All errors except the "E404" are re-thrown.
35
- if ( !error.toString().includes( 'code E404' ) ) {
36
- throw error;
37
- }
38
-
39
- // Npm >= 8.13.0 throws an "E404" error if a version does not exist.
40
- // Npm < 8.13.0 should never reach this line.
23
+ .catch( () => {
24
+ // When throws, the package does not exist.
41
25
  return true;
42
26
  } );
43
27
  }
@@ -11,7 +11,7 @@ import provideToken from './providetoken.js';
11
11
  *
12
12
  * If the user choices a GitHub, required token also has to be provided.
13
13
  *
14
- * @returns {Promise.<Object>}
14
+ * @returns {Promise.<object>}
15
15
  */
16
16
  export default async function configureReleaseOptions() {
17
17
  const options = {};
@@ -8,7 +8,7 @@ import inquirer from 'inquirer';
8
8
  /**
9
9
  * Asks a user for a confirmation for including a package that does not contain all required files.
10
10
  *
11
- * @returns {Promise.<Boolean>}
11
+ * @returns {Promise.<boolean>}
12
12
  */
13
13
  export default async function confirmIncludingPackage() {
14
14
  const confirmQuestion = {
@@ -9,9 +9,9 @@ import chalk from 'chalk';
9
9
  /**
10
10
  * Asks a user for a confirmation for updating and tagging versions of the packages.
11
11
  *
12
- * @param {String} versionTag A version tag based on a package version specified in `package.json`.
13
- * @param {String} npmTag A tag typed by the user when using the release tools.
14
- * @returns {Promise.<Boolean>}
12
+ * @param {string} versionTag A version tag based on a package version specified in `package.json`.
13
+ * @param {string} npmTag A tag typed by the user when using the release tools.
14
+ * @returns {Promise.<boolean>}
15
15
  */
16
16
  export default function confirmNpmTag( versionTag, npmTag ) {
17
17
  const areVersionsEqual = versionTag === npmTag;
@@ -10,9 +10,9 @@ import { CLI_COMMIT_INDENT_SIZE, CLI_INDENT_SIZE } from './constants.js';
10
10
 
11
11
  /**
12
12
  * @param {Array.<Commit>|Set.<Commit>} commits
13
- * @param {Object} [options={}]
14
- * @param {Boolean} [options.attachLinkToCommit=false] Whether to attach a link to parsed commit.
15
- * @param {Number} [options.indentLevel=1] The indent level.
13
+ * @param {object} [options={}]
14
+ * @param {boolean} [options.attachLinkToCommit=false] Whether to attach a link to parsed commit.
15
+ * @param {number} [options.indentLevel=1] The indent level.
16
16
  */
17
17
  export default function displayCommits( commits, options = {} ) {
18
18
  const log = logger();
@@ -28,7 +28,7 @@ export default function displayCommits( commits, options = {} ) {
28
28
  const COMMITS_SEPARATOR = listIndent + chalk.gray( '-'.repeat( 112 ) );
29
29
 
30
30
  // Group of commits by the commit's hash.
31
- /** @type {Map.<String, Set.<Commit>>} */
31
+ /** @type {Map.<string, Set.<Commit>>} */
32
32
  const commitGroups = new Map();
33
33
 
34
34
  for ( const singleCommit of commits ) {
@@ -10,8 +10,8 @@ import upath from 'upath';
10
10
  import os from 'os';
11
11
  import fs from 'fs/promises';
12
12
  import { Worker } from 'worker_threads';
13
- import { glob } from 'glob';
14
13
  import { registerAbortController, deregisterAbortController } from './abortcontroller.js';
14
+ import findPathsToPackages from './findpathstopackages.js';
15
15
 
16
16
  const WORKER_SCRIPT = new URL( './parallelworker.js', import.meta.url );
17
17
 
@@ -23,17 +23,17 @@ const WORKER_SCRIPT = new URL( './parallelworker.js', import.meta.url );
23
23
  * Functions cannot be passed to workers. Hence, we store the callback as a Node.js file loaded by workers.
24
24
  *
25
25
  * @see https://nodejs.org/api/worker_threads.html
26
- * @param {Object} options
27
- * @param {String} options.packagesDirectory Relative path to a location of packages to execute a task.
28
- * @param {Function} options.taskToExecute A callback that is executed on all found packages.
26
+ * @param {object} options
27
+ * @param {string} options.packagesDirectory Relative path to a location of packages to execute a task.
28
+ * @param {function} options.taskToExecute A callback that is executed on all found packages.
29
29
  * It receives an absolute path to a package as an argument. It can be synchronous or may return a promise.
30
30
  * @param {ListrTaskObject} [options.listrTask={}] An instance of `ListrTask`.
31
31
  * @param {AbortSignal|null} [options.signal=null] Signal to abort the asynchronous process. If not set, default AbortController is created.
32
- * @param {Object} [options.taskOptions=null] Optional data required by the task.
32
+ * @param {object} [options.taskOptions=null] Optional data required by the task.
33
33
  * @param {ExecuteInParallelPackagesDirectoryFilter|null} [options.packagesDirectoryFilter=null] An optional callback allowing filtering out
34
34
  * directories/packages that should not be touched by the task.
35
- * @param {String} [options.cwd=process.cwd()] Current working directory from which all paths will be resolved.
36
- * @param {Number} [options.concurrency=require( 'os' ).cpus().length / 2] Number of CPUs that will execute the task.
35
+ * @param {string} [options.cwd=process.cwd()] Current working directory from which all paths will be resolved.
36
+ * @param {number} [options.concurrency=require( 'os' ).cpus().length / 2] Number of CPUs that will execute the task.
37
37
  * @returns {Promise}
38
38
  */
39
39
  export default async function executeInParallel( options ) {
@@ -48,17 +48,12 @@ export default async function executeInParallel( options ) {
48
48
  concurrency = os.cpus().length / 2
49
49
  } = options;
50
50
 
51
- const normalizedCwd = upath.toUnix( cwd );
52
- const packages = ( await glob( `${ packagesDirectory }/*/`, {
53
- cwd: normalizedCwd,
54
- absolute: true
55
- } ) ).map( upath.normalize );
56
-
57
- const packagesToProcess = packagesDirectoryFilter ?
58
- packages.filter( packagesDirectoryFilter ) :
59
- packages;
51
+ const concurrencyAsInteger = Math.floor( concurrency ) || 1;
52
+ const packagesToProcess = await findPathsToPackages( cwd, packagesDirectory, {
53
+ packagesDirectoryFilter
54
+ } );
60
55
 
61
- const packagesInThreads = getPackagesGroupedByThreads( packagesToProcess, concurrency );
56
+ const packagesInThreads = getPackagesGroupedByThreads( packagesToProcess, concurrencyAsInteger );
62
57
 
63
58
  const callbackModule = upath.join( cwd, crypto.randomUUID() + '.mjs' );
64
59
  await fs.writeFile( callbackModule, `export default ${ taskToExecute };`, 'utf-8' );
@@ -99,7 +94,7 @@ export default async function executeInParallel( options ) {
99
94
 
100
95
  /**
101
96
  * @param {ListrTaskObject} listrTask
102
- * @param {Number} total
97
+ * @param {number} total
103
98
  * @returns {Function}
104
99
  */
105
100
  function progressFactory( listrTask, total ) {
@@ -112,10 +107,10 @@ function progressFactory( listrTask, total ) {
112
107
  }
113
108
 
114
109
  /**
115
- * @param {Object} options
110
+ * @param {object} options
116
111
  * @param {AbortSignal} options.signal
117
- * @param {Function} options.onPackageDone
118
- * @param {Object} options.workerData
112
+ * @param {function} options.onPackageDone
113
+ * @param {object} options.workerData
119
114
  * @returns {Promise}
120
115
  */
121
116
  function createWorker( { signal, onPackageDone, workerData } ) {
@@ -149,9 +144,9 @@ function createWorker( { signal, onPackageDone, workerData } ) {
149
144
  *
150
145
  * To avoid having packages with a common prefix in a single thread, use a loop for attaching packages to threads.
151
146
  *
152
- * @param {Array.<String>} packages An array of absolute paths to packages.
153
- * @param {Number} concurrency A number of threads.
154
- * @returns {Array.<Array.<String>>}
147
+ * @param {Array.<string>} packages An array of absolute paths to packages.
148
+ * @param {number} concurrency A number of threads.
149
+ * @returns {Array.<Array.<string>>}
155
150
  */
156
151
  function getPackagesGroupedByThreads( packages, concurrency ) {
157
152
  return packages.reduce( ( collection, packageItem, index ) => {
@@ -168,19 +163,19 @@ function getPackagesGroupedByThreads( packages, concurrency ) {
168
163
  }
169
164
 
170
165
  /**
171
- * @typedef {Object} ListrTaskObject
166
+ * @typedef {object} ListrTaskObject
172
167
  *
173
168
  * @see https://listr2.kilic.dev/api/classes/ListrTaskObject.html
174
169
  *
175
- * @property {String} title Title of the task.
170
+ * @property {string} title Title of the task.
176
171
  *
177
- * @property {String} output Update the current output of the task.
172
+ * @property {string} output Update the current output of the task.
178
173
  */
179
174
 
180
175
  /**
181
176
  * @callback ExecuteInParallelPackagesDirectoryFilter
182
177
  *
183
- * @param {String} directoryPath An absolute path to a directory.
178
+ * @param {string} directoryPath An absolute path to a directory.
184
179
  *
185
- * @returns {Boolean} Whether to include (`true`) or skip (`false`) processing the given directory.
180
+ * @returns {boolean} Whether to include (`true`) or skip (`false`) processing the given directory.
186
181
  */
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md.
4
+ */
5
+
6
+ import upath from 'upath';
7
+ import { glob } from 'glob';
8
+
9
+ /**
10
+ * Returns an array containing paths to packages found in the `packagesDirectory` directory.
11
+ *
12
+ * @param {string} cwd
13
+ * @param {string|null} packagesDirectory
14
+ * @param {object} [options={}]
15
+ * @param {boolean} [options.includePackageJson=false]
16
+ * @param {boolean} [options.includeCwd=false]
17
+ * @param {PackagesDirectoryFilter|null} [options.packagesDirectoryFilter=null]
18
+ * @returns {Array.<string>}
19
+ */
20
+ export default async function findPathsToPackages( cwd, packagesDirectory, options = {} ) {
21
+ const {
22
+ includePackageJson = false,
23
+ includeCwd = false,
24
+ packagesDirectoryFilter = null
25
+ } = options;
26
+
27
+ const packagePaths = await getPackages( cwd, packagesDirectory, includePackageJson );
28
+
29
+ if ( includeCwd ) {
30
+ if ( includePackageJson ) {
31
+ packagePaths.push( upath.join( cwd, 'package.json' ) );
32
+ } else {
33
+ packagePaths.push( cwd );
34
+ }
35
+ }
36
+
37
+ const normalizedPaths = packagePaths.map( item => upath.normalize( item ) );
38
+
39
+ if ( packagesDirectoryFilter ) {
40
+ return normalizedPaths.filter( item => packagesDirectoryFilter( item ) );
41
+ }
42
+
43
+ return normalizedPaths;
44
+ }
45
+
46
+ /**
47
+ * @param {string} cwd
48
+ * @param {string|null} packagesDirectory
49
+ * @param {boolean} includePackageJson
50
+ * @returns {Promise.<Array.<string>>}
51
+ */
52
+ function getPackages( cwd, packagesDirectory, includePackageJson ) {
53
+ if ( !packagesDirectory ) {
54
+ return [];
55
+ }
56
+
57
+ const globOptions = {
58
+ cwd: upath.join( cwd, packagesDirectory ),
59
+ absolute: true
60
+ };
61
+
62
+ let pattern = '*/';
63
+
64
+ if ( includePackageJson ) {
65
+ pattern += 'package.json';
66
+ globOptions.nodir = true;
67
+ }
68
+
69
+ return glob( pattern, globOptions );
70
+ }
71
+
72
+ /**
73
+ * @callback PackagesDirectoryFilter
74
+ *
75
+ * @param {string} packageJsonPath An absolute path to a `package.json` file.
76
+ *
77
+ * @returns {boolean} Whether to include (`true`) or skip (`false`) processing the given directory/package.
78
+ */
@@ -14,27 +14,27 @@ const UPDATED_TRANSLATION_COMMIT = '* Updated translations.';
14
14
  *
15
15
  * @param {Array.<Commit>} commits
16
16
  *
17
- * @param {Object} context
18
- * @param {String} context.version Current version for the release.
19
- * @param {String} context.repoUrl The repository URL.
20
- * @param {String} context.currentTag A tag for the current version.
21
- * @param {String} context.commit Commit keyword in the URL.
22
- * @param {String} [context.previousTag] A tag for the previous version.
23
- * @param {Boolean} [context.skipCommitsLink=false] Whether to skip adding links to commit.
24
- * @param {Boolean} [context.skipCompareLink=false] Whether to remove the compare URL in the header.
17
+ * @param {object} context
18
+ * @param {string} context.version Current version for the release.
19
+ * @param {string} context.repoUrl The repository URL.
20
+ * @param {string} context.currentTag A tag for the current version.
21
+ * @param {string} context.commit Commit keyword in the URL.
22
+ * @param {string} [context.previousTag] A tag for the previous version.
23
+ * @param {boolean} [context.skipCommitsLink=false] Whether to skip adding links to commit.
24
+ * @param {boolean} [context.skipCompareLink=false] Whether to remove the compare URL in the header.
25
25
  *
26
- * @param {Object} options
27
- * @param {Object} options.transform
28
- * @param {Function} options.transform.hash A function for mapping the commit's hash.
29
- * @param {Array.<String>|String} options.groupBy A key for grouping the commits.
30
- * @param {Function} options.commitGroupsSort A sort function for the groups.
31
- * @param {Function} options.noteGroupsSort A soft function for the notes.
32
- * @param {String} options.mainTemplate The main template for the changelog.
33
- * @param {String} options.headerPartial The "header" partial used in the main template.
34
- * @param {String} options.commitPartial The "commit" partial used in the main template.
35
- * @param {String} options.footerPartial The "footer" partial used in the main template.
26
+ * @param {object} options
27
+ * @param {object} options.transform
28
+ * @param {function} options.transform.hash A function for mapping the commit's hash.
29
+ * @param {Array.<string>|string} options.groupBy A key for grouping the commits.
30
+ * @param {function} options.commitGroupsSort A sort function for the groups.
31
+ * @param {function} options.noteGroupsSort A soft function for the notes.
32
+ * @param {string} options.mainTemplate The main template for the changelog.
33
+ * @param {string} options.headerPartial The "header" partial used in the main template.
34
+ * @param {string} options.commitPartial The "commit" partial used in the main template.
35
+ * @param {string} options.footerPartial The "footer" partial used in the main template.
36
36
  *
37
- * @returns {Promise.<String>}
37
+ * @returns {Promise.<string>}
38
38
  */
39
39
  export default function generateChangelog( commits, context, options ) {
40
40
  const commitStream = new Readable( { objectMode: true } );
@@ -64,10 +64,10 @@ export default function generateChangelog( commits, context, options ) {
64
64
  /**
65
65
  * Merges multiple "Updated translations." entries into the single commit.
66
66
  *
67
- * @param {String} changelog Generated changelog.
68
- * @param {Object} [options={}]
69
- * @param {Boolean} [options.skipCommitsLink=false] Whether to skip adding links to commit.
70
- * @returns {String}
67
+ * @param {string} changelog Generated changelog.
68
+ * @param {object} [options={}]
69
+ * @param {boolean} [options.skipCommitsLink=false] Whether to skip adding links to commit.
70
+ * @returns {string}
71
71
  */
72
72
  function mergeUpdateTranslationsCommits( changelog, options = {} ) {
73
73
  let foundUpdatedTranslationCommit = false;
@@ -8,8 +8,8 @@ import { tools } from '@ckeditor/ckeditor5-dev-utils';
8
8
  /**
9
9
  * Returns an array with paths to changed files for given commit.
10
10
  *
11
- * @param {String} commitId
12
- * @returns {Array.<String>}
11
+ * @param {string} commitId
12
+ * @returns {Array.<string>}
13
13
  */
14
14
  export default function getChangedFilesForCommit( commitId ) {
15
15
  const gitCommand = `git log -m -1 --name-only --pretty="format:" ${ commitId }`;
@@ -8,8 +8,8 @@ import path from 'path';
8
8
  import { CHANGELOG_FILE } from './constants.js';
9
9
 
10
10
  /**
11
- * @param {String} [cwd=process.cwd()] Where to look for the changelog file.
12
- * @returns {String|null}
11
+ * @param {string} [cwd=process.cwd()] Where to look for the changelog file.
12
+ * @returns {string|null}
13
13
  */
14
14
  export default function getChangelog( cwd = process.cwd() ) {
15
15
  const changelogFile = path.join( cwd, CHANGELOG_FILE );
@@ -9,9 +9,9 @@ import getChangelog from './getchangelog.js';
9
9
  /**
10
10
  * Retrieves changes from the changelog for the given version (tag).
11
11
  *
12
- * @param {String} version
13
- * @param {String} [cwd=process.cwd()] Where to look for the changelog file.
14
- * @returns {String|null}
12
+ * @param {string} version
13
+ * @param {string} [cwd=process.cwd()] Where to look for the changelog file.
14
+ * @returns {string|null}
15
15
  */
16
16
  export default function getChangesForVersion( version, cwd = process.cwd() ) {
17
17
  version = version.replace( /^v/, '' );
@@ -9,15 +9,16 @@ import { getRawCommitsStream } from 'git-raw-commits';
9
9
  import concat from 'concat-stream';
10
10
  import parserOptions from './parseroptions.js';
11
11
  import { tools } from '@ckeditor/ckeditor5-dev-utils';
12
+ import shellEscape from 'shell-escape';
12
13
 
13
14
  /**
14
15
  * Returns a promise that resolves an array of commits since the last tag specified as `options.from`.
15
16
  *
16
- * @param {Function} transformCommit
17
- * @param {Object} options
18
- * @param {String} [options.from] A commit or tag name that will be the first param of the range of commits to collect.
19
- * @param {String} [options.releaseBranch='master'] A name of the branch that should be used for releasing packages.
20
- * @param {String} [options.mainBranch='master'] A name of the main branch in the repository.
17
+ * @param {function} transformCommit
18
+ * @param {object} options
19
+ * @param {string} [options.from] A commit or tag name that will be the first param of the range of commits to collect.
20
+ * @param {string} [options.releaseBranch='master'] A name of the branch that should be used for releasing packages.
21
+ * @param {string} [options.mainBranch='master'] A name of the main branch in the repository.
21
22
  * @returns {Promise.<Array.<Commit>>}
22
23
  */
23
24
  export default function getCommits( transformCommit, options = {} ) {
@@ -39,7 +40,7 @@ export default function getCommits( transformCommit, options = {} ) {
39
40
  } else {
40
41
  // Otherwise, (release branch is other than the main branch) we need to merge arrays of commits.
41
42
  // See: https://github.com/ckeditor/ckeditor5/issues/7492.
42
- const baseCommit = exec( `git merge-base ${ releaseBranch } ${ mainBranch }` ).trim();
43
+ const baseCommit = exec( `git merge-base ${ shellEscape( [ releaseBranch, mainBranch ] ) }` ).trim();
43
44
 
44
45
  const commitPromises = [
45
46
  // 1. Commits from the last release and to the point where the release branch was created (the merge-base commit).
@@ -6,7 +6,7 @@
6
6
  import { format } from 'date-fns';
7
7
 
8
8
  /**
9
- * @returns {String}
9
+ * @returns {string}
10
10
  */
11
11
  export default function getFormattedDate() {
12
12
  return format( new Date(), 'yyyy-MM-dd' );
@@ -7,7 +7,7 @@
7
7
  * Proposes new version based on commits.
8
8
  *
9
9
  * @param {Array.<Commit>} commits
10
- * @returns {String|null}
10
+ * @returns {string|null}
11
11
  */
12
12
  export default function getNewVersionType( commits ) {
13
13
  // No commits = no changes.
@@ -6,11 +6,20 @@
6
6
  import semver from 'semver';
7
7
 
8
8
  /**
9
- * @param {String} version
10
- * @returns {String}
9
+ * Returns a version tag from specified `version`.
10
+ *
11
+ * For the official release, returns the "latest" tag. For a non-official release (pre-release),
12
+ * returns the version tag extracted from the passed version.
13
+ *
14
+ * @param {string} version
15
+ * @returns {string}
11
16
  */
12
17
  export default function getNpmTagFromVersion( version ) {
13
18
  const [ versionTag ] = semver.prerelease( version ) || [ 'latest' ];
14
19
 
20
+ if ( versionTag.startsWith( 'nightly' ) ) {
21
+ return 'nightly';
22
+ }
23
+
15
24
  return versionTag;
16
25
  }
@@ -12,8 +12,8 @@ import upath from 'upath';
12
12
  * This function is helpful for testing the whole process. Allows mocking the file
13
13
  * instead of create the fixtures.
14
14
  *
15
- * @param {String} [cwd=process.cwd()] Where to look for package.json.
16
- * @returns {Object}
15
+ * @param {string} [cwd=process.cwd()] Where to look for package.json.
16
+ * @returns {object}
17
17
  */
18
18
  export default function getPackageJson( cwd = process.cwd() ) {
19
19
  let pkgJsonPath = cwd;
@@ -17,13 +17,13 @@ import getPackageJson from './getpackagejson.js';
17
17
  * - The second one is marked as `skipped` and means that packages should not be processed. They were listed as packages to skip
18
18
  * (`options.skipPackages` or don't mach to `options.scope`).
19
19
  *
20
- * @param {Object} options
21
- * @param {String} options.cwd Current work directory.
22
- * @param {String|null} options.packages Name of directory where to look for packages. If `null`, only repository specified under
20
+ * @param {object} options
21
+ * @param {string} options.cwd Current work directory.
22
+ * @param {string|null} options.packages Name of directory where to look for packages. If `null`, only repository specified under
23
23
  * `options.cwd` will be returned.
24
- * @param {String|Array.<String>} options.skipPackages Glob pattern(s) which describes which packages should be skipped.
25
- * @param {String} [options.scope] Package names have to match to specified glob pattern.
26
- * @param {Boolean} [options.skipMainRepository=false] If set on true, package found in `options.cwd` will be skipped.
24
+ * @param {string|Array.<string>} options.skipPackages Glob pattern(s) which describes which packages should be skipped.
25
+ * @param {string} [options.scope] Package names have to match to specified glob pattern.
26
+ * @param {boolean} [options.skipMainRepository=false] If set on true, package found in `options.cwd` will be skipped.
27
27
  * @returns {PathsCollection}
28
28
  */
29
29
  export default function getPackagesPaths( options ) {
@@ -80,9 +80,9 @@ export default function getPackagesPaths( options ) {
80
80
  }
81
81
 
82
82
  /**
83
- * @typedef {Object} PathsCollection
83
+ * @typedef {object} PathsCollection
84
84
  *
85
- * @property {Set.<String>} matched Packages that match given criteria.
85
+ * @property {Set.<string>} matched Packages that match given criteria.
86
86
  *
87
- * @property {Set.<String>} skipped Packages that do not match given criteria.
87
+ * @property {Set.<string>} skipped Packages that do not match given criteria.
88
88
  */
@@ -15,7 +15,7 @@ const templatePath = path.join( __dirname, '..', 'templates' );
15
15
 
16
16
  /**
17
17
  * @param {WriterOptionsTransformCallback} transform
18
- * @returns {Object}
18
+ * @returns {object}
19
19
  */
20
20
  export default function getWriterOptions( transform ) {
21
21
  return {
@@ -3,23 +3,21 @@
3
3
  * For licensing, see LICENSE.md.
4
4
  */
5
5
 
6
- import { tools } from '@ckeditor/ckeditor5-dev-utils';
7
6
  import semver from 'semver';
8
- import shellEscape from 'shell-escape';
7
+ import pacote from 'pacote';
9
8
 
10
9
  /**
11
10
  * This util aims to verify if the given `packageName` can be published with the given `version` on the `npmTag`.
12
11
  *
13
- * @param {String} packageName
14
- * @param {String} version
15
- * @param {String} npmTag
16
- * @return {Promise.<Boolean>}
12
+ * @param {string} packageName
13
+ * @param {string} version
14
+ * @param {string} npmTag
15
+ * @returns {Promise.<boolean>}
17
16
  */
18
17
  export default async function isVersionPublishableForTag( packageName, version, npmTag ) {
19
- const command = `npm view ${ shellEscape( [ packageName ] ) }@${ shellEscape( [ npmTag ] ) } version --silent`;
20
- const npmVersion = await tools.shExec( command, { async: true, verbosity: 'silent' } )
21
- .then( value => value.trim() )
22
- // An `npmTag` does not exist.
18
+ const npmVersion = await pacote.manifest( `${ packageName }@${ npmTag }` )
19
+ .then( ( { version } ) => version )
20
+ // An `npmTag` does not exist, or it's a first release of a package.
23
21
  .catch( () => null );
24
22
 
25
23
  if ( npmVersion && semver.lte( version, npmVersion ) ) {
@@ -10,8 +10,8 @@ import { parentPort, workerData } from 'worker_threads';
10
10
  // Required due to top-level await.
11
11
  ( async () => {
12
12
  /**
13
- * @param {String} callbackModule
14
- * @param {Array.<String>} packages
13
+ * @param {string} callbackModule
14
+ * @param {Array.<string>} packages
15
15
  */
16
16
  const { default: callback } = await import( workerData.callbackModule );
17
17
 
@@ -7,23 +7,29 @@ import inquirer from 'inquirer';
7
7
  import semver from 'semver';
8
8
  import chalk from 'chalk';
9
9
  import { CLI_INDENT_SIZE } from './constants.js';
10
+ import checkVersionAvailability from './checkversionavailability.js';
10
11
 
11
12
  /**
12
13
  * Asks a user for providing the new version for a major release.
13
14
  *
14
- * @param {String} version
15
- * @param {String} foundPackage
16
- * @param {String} bumpType
17
- * @param {Object} [options={}]
18
- * @param {Number} [options.indentLevel=0] The indent level.
19
- * @returns {Promise.<String>}
15
+ * @param {object} options
16
+ * @param {string} options.packageName
17
+ * @param {string} options.version
18
+ * @param {string} options.bumpType
19
+ * @param {number} [options.indentLevel=0] The indent level.
20
+ * @returns {Promise.<string>}
20
21
  */
21
- export default async function provideNewVersionForMonoRepository( version, foundPackage, bumpType, options = {} ) {
22
- const indentLevel = options.indentLevel || 0;
23
- const suggestedVersion = semver.inc( version, bumpType );
22
+ export default async function provideNewVersionForMonoRepository( options ) {
23
+ const {
24
+ version,
25
+ packageName,
26
+ bumpType,
27
+ indentLevel = 0
28
+ } = options;
24
29
 
30
+ const suggestedVersion = semver.inc( version, bumpType );
25
31
  const message = 'Type the new version ' +
26
- `(current highest: "${ version }" found in "${ chalk.underline( foundPackage ) }", suggested: "${ suggestedVersion }"):`;
32
+ `(current highest: "${ version }" found in "${ chalk.underline( packageName ) }", suggested: "${ suggestedVersion }"):`;
27
33
 
28
34
  const versionQuestion = {
29
35
  type: 'input',
@@ -35,12 +41,22 @@ export default async function provideNewVersionForMonoRepository( version, found
35
41
  return input.trim();
36
42
  },
37
43
 
38
- validate( input ) {
44
+ async validate( input ) {
39
45
  if ( !semver.valid( input ) ) {
40
46
  return 'Please provide a valid version.';
41
47
  }
42
48
 
43
- return semver.gt( input, version ) ? true : `Provided version must be higher than "${ version }".`;
49
+ if ( !semver.gt( input, version ) ) {
50
+ return `Provided version must be higher than "${ version }".`;
51
+ }
52
+
53
+ const isAvailable = await checkVersionAvailability( input, packageName );
54
+
55
+ if ( !isAvailable ) {
56
+ return 'Given version is already taken.';
57
+ }
58
+
59
+ return true;
44
60
  },
45
61
  prefix: ' '.repeat( indentLevel * CLI_INDENT_SIZE ) + chalk.cyan( '?' )
46
62
  };