@ckeditor/ckeditor5-dev-release-tools 43.0.0 → 44.0.0-alpha.1

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 (53) hide show
  1. package/lib/index.js +23 -52
  2. package/lib/tasks/cleanuppackages.js +5 -7
  3. package/lib/tasks/commitandtag.js +7 -7
  4. package/lib/tasks/creategithubrelease.js +6 -6
  5. package/lib/tasks/generatechangelogformonorepository.js +44 -40
  6. package/lib/tasks/generatechangelogforsinglepackage.js +35 -31
  7. package/lib/tasks/preparerepository.js +11 -12
  8. package/lib/tasks/publishpackages.js +10 -12
  9. package/lib/tasks/push.js +4 -6
  10. package/lib/tasks/reassignnpmtags.js +11 -13
  11. package/lib/tasks/updatedependencies.js +5 -7
  12. package/lib/tasks/updateversions.js +8 -8
  13. package/lib/tasks/verifypackagespublishedcorrectly.js +6 -8
  14. package/lib/utils/abortcontroller.js +2 -11
  15. package/lib/utils/assertfilestopublish.js +5 -7
  16. package/lib/utils/assertnpmauthorization.js +3 -5
  17. package/lib/utils/assertnpmtag.js +5 -7
  18. package/lib/utils/assertpackages.js +4 -6
  19. package/lib/utils/checkversionavailability.js +4 -6
  20. package/lib/utils/configurereleaseoptions.js +43 -0
  21. package/lib/utils/confirmincludingpackage.js +24 -0
  22. package/lib/utils/confirmnpmtag.js +32 -0
  23. package/lib/utils/constants.js +26 -0
  24. package/lib/utils/displaycommits.js +9 -11
  25. package/lib/utils/displayskippedpackages.js +7 -9
  26. package/lib/utils/executeinparallel.js +13 -14
  27. package/lib/utils/generatechangelog.js +6 -8
  28. package/lib/utils/getchangedfilesforcommit.js +3 -5
  29. package/lib/utils/getchangelog.js +22 -0
  30. package/lib/utils/getchangesforversion.js +28 -0
  31. package/lib/utils/getcommits.js +12 -14
  32. package/lib/utils/getformatteddate.js +13 -0
  33. package/lib/utils/getnewversiontype.js +2 -4
  34. package/lib/utils/getnpmtagfromversion.js +3 -5
  35. package/lib/utils/getpackagejson.js +4 -6
  36. package/lib/utils/getpackagespaths.js +7 -9
  37. package/lib/utils/getwriteroptions.js +16 -7
  38. package/lib/utils/isversionpublishablefortag.js +5 -5
  39. package/lib/utils/{parallelworker.cjs → parallelworker.js} +3 -4
  40. package/lib/utils/parseroptions.js +1 -3
  41. package/lib/utils/providenewversionformonorepository.js +51 -0
  42. package/lib/utils/providetoken.js +26 -0
  43. package/lib/utils/provideversion.js +98 -0
  44. package/lib/utils/publishpackageonnpmcallback.js +10 -12
  45. package/lib/utils/savechangelog.js +18 -0
  46. package/lib/utils/transformcommitfactory.js +5 -7
  47. package/lib/utils/transformcommitutils.js +142 -147
  48. package/lib/utils/truncatechangelog.js +42 -0
  49. package/lib/utils/validaterepositorytorelease.js +3 -5
  50. package/lib/utils/versions.js +122 -128
  51. package/package.json +16 -15
  52. package/lib/utils/changelog.js +0 -109
  53. package/lib/utils/cli.js +0 -349
@@ -3,161 +3,156 @@
3
3
  * For licensing, see LICENSE.md.
4
4
  */
5
5
 
6
- 'use strict';
7
-
8
- const getPackageJson = require( './getpackagejson' );
9
-
10
- const transformCommitUtils = {
11
- /**
12
- * A regexp for extracting additional changelog entries from the single commit.
13
- * Prefixes of the commit must be synchronized the `getCommitType()` util.
14
- */
15
- MULTI_ENTRIES_COMMIT_REGEXP: /(?:Feature|Other|Fix|Docs|Internal|Tests|Revert|Release)(?: \([\w\-, ]+?\))?:/g,
16
-
17
- /**
18
- * Map of available types of the commits.
19
- * Types marked as `false` will be ignored during generating the changelog.
20
- */
21
- availableCommitTypes: new Map( [
22
- [ 'Fix', true ],
23
- [ 'Feature', true ],
24
- [ 'Other', true ],
25
-
26
- [ 'Docs', false ],
27
- [ 'Internal', false ],
28
- [ 'Tests', false ],
29
- [ 'Revert', false ],
30
- [ 'Release', false ]
31
- ] ),
32
-
33
- /**
34
- * Order of messages generated in changelog.
35
- */
36
- typesOrder: {
37
- 'Features': 1,
38
- 'Bug fixes': 2,
39
- 'Other changes': 3,
40
-
41
- 'MAJOR BREAKING CHANGES': 1,
42
- 'MINOR BREAKING CHANGES': 2,
43
- 'BREAKING CHANGES': 3
44
- },
45
-
46
- /**
47
- * Returns an order of a message in the changelog.
48
- *
49
- * @param {String} title
50
- * @returns {Number}
51
- */
52
- getTypeOrder( title ) {
53
- for ( const typeTitle of Object.keys( transformCommitUtils.typesOrder ) ) {
54
- if ( title.startsWith( typeTitle ) ) {
55
- return transformCommitUtils.typesOrder[ typeTitle ];
56
- }
6
+ import getPackageJson from './getpackagejson.js';
7
+
8
+ /**
9
+ * A regexp for extracting additional changelog entries from the single commit.
10
+ * Prefixes of the commit must be synchronized the `getCommitType()` util.
11
+ */
12
+ export const MULTI_ENTRIES_COMMIT_REGEXP = /(?:Feature|Other|Fix|Docs|Internal|Tests|Revert|Release)(?: \([\w\-, ]+?\))?:/g;
13
+
14
+ /**
15
+ * Map of available types of the commits.
16
+ * Types marked as `false` will be ignored during generating the changelog.
17
+ */
18
+ export const availableCommitTypes = new Map( [
19
+ [ 'Fix', true ],
20
+ [ 'Feature', true ],
21
+ [ 'Other', true ],
22
+
23
+ [ 'Docs', false ],
24
+ [ 'Internal', false ],
25
+ [ 'Tests', false ],
26
+ [ 'Revert', false ],
27
+ [ 'Release', false ]
28
+ ] );
29
+
30
+ /**
31
+ * Order of messages generated in changelog.
32
+ */
33
+ export const typesOrder = {
34
+ 'Features': 1,
35
+ 'Bug fixes': 2,
36
+ 'Other changes': 3,
37
+
38
+ 'MAJOR BREAKING CHANGES': 1,
39
+ 'MINOR BREAKING CHANGES': 2,
40
+ 'BREAKING CHANGES': 3
41
+ };
42
+
43
+ /**
44
+ * Returns an order of a message in the changelog.
45
+ *
46
+ * @param {String} title
47
+ * @returns {Number}
48
+ */
49
+ export function getTypeOrder( title ) {
50
+ for ( const typeTitle of Object.keys( typesOrder ) ) {
51
+ if ( title.startsWith( typeTitle ) ) {
52
+ return typesOrder[ typeTitle ];
57
53
  }
54
+ }
55
+
56
+ return 10;
57
+ }
58
58
 
59
- return 10;
60
- },
61
-
62
- /**
63
- * Replaces reference to the user (`@name`) with a link to the user's profile.
64
- *
65
- * @param {String} comment
66
- * @returns {String}
67
- */
68
- linkToGithubUser( comment ) {
69
- return comment.replace( /(^|[\s(])@([\w-]+)(?![/\w-])/ig, ( matchedText, charBefore, nickName ) => {
70
- return `${ charBefore }[@${ nickName }](https://github.com/${ nickName })`;
71
- } );
72
- },
73
-
74
- /**
75
- * Replaces reference to issue (#ID) with a link to the issue.
76
- * If comment matches to "organization/repository#ID", link will lead to the specified repository.
77
- *
78
- * @param {String} comment
79
- * @returns {String}
80
- */
81
- linkToGithubIssue( comment ) {
82
- return comment.replace( /(\/?[\w-]+\/[\w-]+)?#([\d]+)(?=$|[\s,.)\]])/igm, ( matchedText, maybeRepository, issueId ) => {
83
- if ( maybeRepository ) {
84
- if ( maybeRepository.startsWith( '/' ) ) {
85
- return matchedText;
86
- }
87
-
88
- return `[${ maybeRepository }#${ issueId }](https://github.com/${ maybeRepository }/issues/${ issueId })`;
59
+ /**
60
+ * Replaces reference to the user (`@name`) with a link to the user's profile.
61
+ *
62
+ * @param {String} comment
63
+ * @returns {String}
64
+ */
65
+ export function linkToGithubUser( comment ) {
66
+ return comment.replace( /(^|[\s(])@([\w-]+)(?![/\w-])/ig, ( matchedText, charBefore, nickName ) => {
67
+ return `${ charBefore }[@${ nickName }](https://github.com/${ nickName })`;
68
+ } );
69
+ }
70
+
71
+ /**
72
+ * Replaces reference to issue (#ID) with a link to the issue.
73
+ * If comment matches to "organization/repository#ID", link will lead to the specified repository.
74
+ *
75
+ * @param {String} comment
76
+ * @returns {String}
77
+ */
78
+ export function linkToGithubIssue( comment ) {
79
+ return comment.replace( /(\/?[\w-]+\/[\w-]+)?#([\d]+)(?=$|[\s,.)\]])/igm, ( matchedText, maybeRepository, issueId ) => {
80
+ if ( maybeRepository ) {
81
+ if ( maybeRepository.startsWith( '/' ) ) {
82
+ return matchedText;
89
83
  }
90
84
 
91
- const repositoryUrl = transformCommitUtils.getRepositoryUrl();
92
-
93
- // But if doesn't, let's add it.
94
- return `[#${ issueId }](${ repositoryUrl }/issues/${ issueId })`;
95
- } );
96
- },
97
-
98
- /**
99
- * Changes a singular type of commit to plural which will be displayed in a changelog.
100
- *
101
- * The switch cases must be synchronized with the `MULTI_ENTRIES_COMMIT_REGEXP` regexp.
102
- *
103
- * @param {String} commitType
104
- * @returns {String}
105
- */
106
- getCommitType( commitType ) {
107
- switch ( commitType ) {
108
- case 'Feature':
109
- return 'Features';
110
-
111
- case 'Fix':
112
- return 'Bug fixes';
113
-
114
- case 'Other':
115
- return 'Other changes';
116
-
117
- default:
118
- throw new Error( `Given invalid type of commit ("${ commitType }").` );
119
- }
120
- },
121
-
122
- /**
123
- * @param {String} sentence
124
- * @param {Number} length
125
- * @returns {String}
126
- */
127
- truncate( sentence, length ) {
128
- if ( sentence.length <= length ) {
129
- return sentence;
85
+ return `[${ maybeRepository }#${ issueId }](https://github.com/${ maybeRepository }/issues/${ issueId })`;
130
86
  }
131
87
 
132
- return sentence.slice( 0, length - 3 ).trim() + '...';
133
- },
134
-
135
- /**
136
- * Returns a URL to the repository whether the commit is being parsed.
137
- *
138
- * @param {String} [cwd=process.cwd()]
139
- * @returns {String}
140
- */
141
- getRepositoryUrl( cwd = process.cwd() ) {
142
- const packageJson = getPackageJson( cwd );
143
-
144
- // Due to merging our issue trackers, `packageJson.bugs` will point to the same place for every package.
145
- // We cannot rely on this value anymore. See: https://github.com/ckeditor/ckeditor5/issues/1988.
146
- // Instead of we can take a value from `packageJson.repository` and adjust it to match to our requirements.
147
- let repositoryUrl = ( typeof packageJson.repository === 'object' ) ? packageJson.repository.url : packageJson.repository;
148
-
149
- if ( !repositoryUrl ) {
150
- throw new Error( `The package.json for "${ packageJson.name }" must contain the "repository" property.` );
151
- }
88
+ const repositoryUrl = getRepositoryUrl();
89
+
90
+ // But if doesn't, let's add it.
91
+ return `[#${ issueId }](${ repositoryUrl }/issues/${ issueId })`;
92
+ } );
93
+ }
94
+
95
+ /**
96
+ * Changes a singular type of commit to plural which will be displayed in a changelog.
97
+ *
98
+ * The switch cases must be synchronized with the `MULTI_ENTRIES_COMMIT_REGEXP` regexp.
99
+ *
100
+ * @param {String} commitType
101
+ * @returns {String}
102
+ */
103
+ export function getCommitType( commitType ) {
104
+ switch ( commitType ) {
105
+ case 'Feature':
106
+ return 'Features';
152
107
 
153
- // If the value ends with ".git", we need to remove it.
154
- repositoryUrl = repositoryUrl.replace( /\.git$/, '' );
108
+ case 'Fix':
109
+ return 'Bug fixes';
155
110
 
156
- // Remove "/issues" suffix as well.
157
- repositoryUrl = repositoryUrl.replace( /\/issues/, '' );
111
+ case 'Other':
112
+ return 'Other changes';
158
113
 
159
- return repositoryUrl;
114
+ default:
115
+ throw new Error( `Given invalid type of commit ("${ commitType }").` );
160
116
  }
161
- };
117
+ }
118
+
119
+ /**
120
+ * @param {String} sentence
121
+ * @param {Number} length
122
+ * @returns {String}
123
+ */
124
+ export function truncate( sentence, length ) {
125
+ if ( sentence.length <= length ) {
126
+ return sentence;
127
+ }
128
+
129
+ return sentence.slice( 0, length - 3 ).trim() + '...';
130
+ }
131
+
132
+ /**
133
+ * Returns a URL to the repository whether the commit is being parsed.
134
+ *
135
+ * @param {String} [cwd=process.cwd()]
136
+ * @returns {String}
137
+ */
138
+ export function getRepositoryUrl( cwd = process.cwd() ) {
139
+ const packageJson = getPackageJson( cwd );
140
+
141
+ // Due to merging our issue trackers, `packageJson.bugs` will point to the same place for every package.
142
+ // We cannot rely on this value anymore. See: https://github.com/ckeditor/ckeditor5/issues/1988.
143
+ // Instead of we can take a value from `packageJson.repository` and adjust it to match to our requirements.
144
+ let repositoryUrl = ( typeof packageJson.repository === 'object' ) ? packageJson.repository.url : packageJson.repository;
145
+
146
+ if ( !repositoryUrl ) {
147
+ throw new Error( `The package.json for "${ packageJson.name }" must contain the "repository" property.` );
148
+ }
149
+
150
+ // If the value ends with ".git", we need to remove it.
151
+ repositoryUrl = repositoryUrl.replace( /\.git$/, '' );
152
+
153
+ // Remove "/issues" suffix as well.
154
+ repositoryUrl = repositoryUrl.replace( /\/issues/, '' );
155
+
156
+ return repositoryUrl;
157
+ }
162
158
 
163
- module.exports = transformCommitUtils;
@@ -0,0 +1,42 @@
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 { CHANGELOG_HEADER } from './constants.js';
7
+ import { getRepositoryUrl } from './transformcommitutils.js';
8
+ import saveChangelog from './savechangelog.js';
9
+ import getChangelog from './getchangelog.js';
10
+
11
+ /**
12
+ * @param {Number} length
13
+ * @param {String} [cwd=process.cwd()] Where to look for the changelog file.
14
+ */
15
+ export default function truncateChangelog( length, cwd = process.cwd() ) {
16
+ const changelog = getChangelog( cwd );
17
+
18
+ if ( !changelog ) {
19
+ return;
20
+ }
21
+
22
+ const entryHeader = '## [\\s\\S]+?';
23
+ const entryHeaderRegexp = new RegExp( `\\n(${ entryHeader })(?=\\n${ entryHeader }|$)`, 'g' );
24
+
25
+ const entries = [ ...changelog.matchAll( entryHeaderRegexp ) ]
26
+ .filter( match => match && match[ 1 ] )
27
+ .map( match => match[ 1 ] );
28
+
29
+ if ( !entries.length ) {
30
+ return;
31
+ }
32
+
33
+ const truncatedEntries = entries.slice( 0, length );
34
+
35
+ const changelogFooter = entries.length > truncatedEntries.length ?
36
+ `\n\n---\n\nTo see all releases, visit the [release page](${ getRepositoryUrl( cwd ) }/releases).\n` :
37
+ '\n';
38
+
39
+ const truncatedChangelog = CHANGELOG_HEADER + truncatedEntries.join( '\n' ).trim() + changelogFooter;
40
+
41
+ saveChangelog( truncatedChangelog, cwd );
42
+ }
@@ -3,9 +3,7 @@
3
3
  * For licensing, see LICENSE.md.
4
4
  */
5
5
 
6
- 'use strict';
7
-
8
- const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
6
+ import { tools } from '@ckeditor/ckeditor5-dev-utils';
9
7
 
10
8
  /**
11
9
  * @param {Object} options
@@ -15,7 +13,7 @@ const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
15
13
  * @param {String} [options.branch='master'] A name of the branch that should be used for releasing packages.
16
14
  * @returns {Promise.<Array.<String>>}
17
15
  */
18
- module.exports = async function validateRepositoryToRelease( options ) {
16
+ export default async function validateRepositoryToRelease( options ) {
19
17
  const {
20
18
  version,
21
19
  changes,
@@ -56,4 +54,4 @@ module.exports = async function validateRepositoryToRelease( options ) {
56
54
  async function exec( command ) {
57
55
  return tools.shExec( command, { verbosity: 'error', async: true } );
58
56
  }
59
- };
57
+ }
@@ -3,136 +3,130 @@
3
3
  * For licensing, see LICENSE.md.
4
4
  */
5
5
 
6
- 'use strict';
7
-
8
- const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
9
- const changelogUtils = require( './changelog' );
10
- const getPackageJson = require( './getpackagejson' );
11
-
12
- const versions = {
13
- /**
14
- * Returns a last created version in changelog file.
15
- *
16
- * @param {String} [cwd=process.cwd()] Where to look for the changelog file.
17
- * @returns {String|null}
18
- */
19
- getLastFromChangelog( cwd = process.cwd() ) {
20
- const changelog = changelogUtils.getChangelog( cwd );
21
-
22
- if ( !changelog ) {
23
- return null;
24
- }
25
-
26
- const regexp = /\n## \[?([\da-z.\-+]+)/i;
27
- const matches = changelog.match( regexp );
28
-
29
- return matches ? matches[ 1 ] : null;
30
- },
31
-
32
- /**
33
- * Returns the current (latest) pre-release version that matches the provided release identifier.
34
- * If the package does not have any pre-releases with the provided identifier yet, `null` is returned.
35
- *
36
- * @param {ReleaseIdentifier} releaseIdentifier
37
- * @param {String} [cwd=process.cwd()]
38
- * @returns {Promise.<String|null>}
39
- */
40
- getLastPreRelease( releaseIdentifier, cwd = process.cwd() ) {
41
- const packageName = getPackageJson( cwd ).name;
42
-
43
- return tools.shExec( `npm view ${ packageName } versions --json`, { verbosity: 'silent', async: true } )
44
- .then( result => {
45
- const lastVersion = JSON.parse( result )
46
- .filter( version => version.startsWith( releaseIdentifier ) )
47
- .sort( ( a, b ) => a.localeCompare( b, undefined, { numeric: true } ) )
48
- .pop();
49
-
50
- return lastVersion || null;
51
- } )
52
- .catch( () => null );
53
- },
54
-
55
- /**
56
- * Returns the current (latest) nightly version in the format of "0.0.0-nightly-YYYYMMDD.X", where the "YYYYMMDD" is the date of the
57
- * last nightly release and the "X" is the sequential number starting from 0. If the package does not have any nightly releases yet,
58
- * `null` is returned.
59
- *
60
- * @param {String} [cwd=process.cwd()]
61
- * @returns {Promise.<String|null>}
62
- */
63
- getLastNightly( cwd = process.cwd() ) {
64
- return versions.getLastPreRelease( '0.0.0-nightly', cwd );
65
- },
66
-
67
- /**
68
- * Returns the next available pre-release version that matches the following format: "<releaseIdentifier>.X", where "X" is the
69
- * next available pre-release sequential number starting from 0.
70
- *
71
- * @param {ReleaseIdentifier} releaseIdentifier
72
- * @param {String} [cwd=process.cwd()]
73
- * @returns {Promise<String>}
74
- */
75
- async getNextPreRelease( releaseIdentifier, cwd = process.cwd() ) {
76
- const currentPreReleaseVersion = await versions.getLastPreRelease( releaseIdentifier, cwd );
77
-
78
- if ( !currentPreReleaseVersion ) {
79
- return `${ releaseIdentifier }.0`;
80
- }
81
-
82
- const currentPreReleaseVersionTokens = currentPreReleaseVersion.split( '.' );
83
- const currentPreReleaseSequenceNumber = currentPreReleaseVersionTokens.pop();
84
- const currentPreReleaseIdentifier = currentPreReleaseVersionTokens.join( '.' );
85
- const nextPreReleaseSequenceNumber = Number( currentPreReleaseSequenceNumber ) + 1;
86
-
87
- return `${ currentPreReleaseIdentifier }.${ nextPreReleaseSequenceNumber }`;
88
- },
89
-
90
- /**
91
- * Returns the next available nightly version in the format of "0.0.0-nightly-YYYYMMDD.X", where the "YYYYMMDD" is the current date for
92
- * the nightly release and the "X" is the sequential number starting from 0.
93
- *
94
- * @param {String} [cwd=process.cwd()]
95
- * @returns {Promise<String>}
96
- */
97
- async getNextNightly( cwd = process.cwd() ) {
98
- const today = new Date();
99
- const year = today.getFullYear().toString();
100
- const month = ( today.getMonth() + 1 ).toString().padStart( 2, '0' );
101
- const day = today.getDate().toString().padStart( 2, '0' );
102
-
103
- const nextNightlyReleaseIdentifier = `0.0.0-nightly-${ year }${ month }${ day }`;
104
-
105
- return versions.getNextPreRelease( nextNightlyReleaseIdentifier, cwd );
106
- },
107
-
108
- /**
109
- * Returns a name of the last created tag.
110
- *
111
- * @returns {String|null}
112
- */
113
- getLastTagFromGit() {
114
- try {
115
- const lastTag = tools.shExec( 'git describe --abbrev=0 --tags 2> /dev/null', { verbosity: 'error' } );
116
-
117
- return lastTag.trim().replace( /^v/, '' ) || null;
118
- } catch ( err ) {
119
- /* istanbul ignore next */
120
- return null;
121
- }
122
- },
123
-
124
- /**
125
- * Returns version of current package from `package.json`.
126
- *
127
- * @param {String} [cwd=process.cwd()] Current work directory.
128
- * @returns {String}
129
- */
130
- getCurrent( cwd = process.cwd() ) {
131
- return getPackageJson( cwd ).version;
6
+ import { tools } from '@ckeditor/ckeditor5-dev-utils';
7
+ import getChangelog from './getchangelog.js';
8
+ import getPackageJson from './getpackagejson.js';
9
+
10
+ /**
11
+ * Returns a last created version in changelog file.
12
+ *
13
+ * @param {String} [cwd=process.cwd()] Where to look for the changelog file.
14
+ * @returns {String|null}
15
+ */
16
+ export function getLastFromChangelog( cwd = process.cwd() ) {
17
+ const changelog = getChangelog( cwd );
18
+
19
+ if ( !changelog ) {
20
+ return null;
132
21
  }
133
- };
134
22
 
135
- module.exports = versions;
23
+ const regexp = /\n## \[?([\da-z.\-+]+)/i;
24
+ const matches = changelog.match( regexp );
25
+
26
+ return matches ? matches[ 1 ] : null;
27
+ }
28
+
29
+ /**
30
+ * Returns the current (latest) pre-release version that matches the provided release identifier.
31
+ * If the package does not have any pre-releases with the provided identifier yet, `null` is returned.
32
+ *
33
+ * @param {ReleaseIdentifier} releaseIdentifier
34
+ * @param {String} [cwd=process.cwd()]
35
+ * @returns {Promise.<String|null>}
36
+ */
37
+ export function getLastPreRelease( releaseIdentifier, cwd = process.cwd() ) {
38
+ const packageName = getPackageJson( cwd ).name;
39
+
40
+ return tools.shExec( `npm view ${ packageName } versions --json`, { verbosity: 'silent', async: true } )
41
+ .then( result => {
42
+ const lastVersion = JSON.parse( result )
43
+ .filter( version => version.startsWith( releaseIdentifier ) )
44
+ .sort( ( a, b ) => a.localeCompare( b, undefined, { numeric: true } ) )
45
+ .pop();
46
+
47
+ return lastVersion || null;
48
+ } )
49
+ .catch( () => null );
50
+ }
51
+
52
+ /**
53
+ * Returns the current (latest) nightly version in the format of "0.0.0-nightly-YYYYMMDD.X", where the "YYYYMMDD" is the date of the
54
+ * last nightly release and the "X" is the sequential number starting from 0. If the package does not have any nightly releases yet,
55
+ * `null` is returned.
56
+ *
57
+ * @param {String} [cwd=process.cwd()]
58
+ * @returns {Promise.<String|null>}
59
+ */
60
+ export function getLastNightly( cwd = process.cwd() ) {
61
+ return getLastPreRelease( '0.0.0-nightly', cwd );
62
+ }
63
+
64
+ /**
65
+ * Returns the next available pre-release version that matches the following format: "<releaseIdentifier>.X", where "X" is the
66
+ * next available pre-release sequential number starting from 0.
67
+ *
68
+ * @param {ReleaseIdentifier} releaseIdentifier
69
+ * @param {String} [cwd=process.cwd()]
70
+ * @returns {Promise<String>}
71
+ */
72
+ export async function getNextPreRelease( releaseIdentifier, cwd = process.cwd() ) {
73
+ const currentPreReleaseVersion = await getLastPreRelease( releaseIdentifier, cwd );
74
+
75
+ if ( !currentPreReleaseVersion ) {
76
+ return `${ releaseIdentifier }.0`;
77
+ }
78
+
79
+ const currentPreReleaseVersionTokens = currentPreReleaseVersion.split( '.' );
80
+ const currentPreReleaseSequenceNumber = currentPreReleaseVersionTokens.pop();
81
+ const currentPreReleaseIdentifier = currentPreReleaseVersionTokens.join( '.' );
82
+ const nextPreReleaseSequenceNumber = Number( currentPreReleaseSequenceNumber ) + 1;
83
+
84
+ return `${ currentPreReleaseIdentifier }.${ nextPreReleaseSequenceNumber }`;
85
+ }
86
+
87
+ /**
88
+ * Returns the next available nightly version in the format of "0.0.0-nightly-YYYYMMDD.X", where the "YYYYMMDD" is the current date for
89
+ * the nightly release and the "X" is the sequential number starting from 0.
90
+ *
91
+ * @param {String} [cwd=process.cwd()]
92
+ * @returns {Promise<String>}
93
+ */
94
+ export async function getNextNightly( cwd = process.cwd() ) {
95
+ const today = new Date();
96
+ const year = today.getFullYear().toString();
97
+ const month = ( today.getMonth() + 1 ).toString().padStart( 2, '0' );
98
+ const day = today.getDate().toString().padStart( 2, '0' );
99
+
100
+ const nextNightlyReleaseIdentifier = `0.0.0-nightly-${ year }${ month }${ day }`;
101
+
102
+ return getNextPreRelease( nextNightlyReleaseIdentifier, cwd );
103
+ }
104
+
105
+ /**
106
+ * Returns a name of the last created tag.
107
+ *
108
+ * @returns {String|null}
109
+ */
110
+ export function getLastTagFromGit() {
111
+ try {
112
+ const lastTag = tools.shExec( 'git describe --abbrev=0 --tags 2> /dev/null', { verbosity: 'error' } );
113
+
114
+ return lastTag.trim().replace( /^v/, '' ) || null;
115
+ } catch ( err ) {
116
+ /* istanbul ignore next */
117
+ return null;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Returns version of current package from `package.json`.
123
+ *
124
+ * @param {String} [cwd=process.cwd()] Current work directory.
125
+ * @returns {String}
126
+ */
127
+ export function getCurrent( cwd = process.cwd() ) {
128
+ return getPackageJson( cwd ).version;
129
+ }
136
130
 
137
131
  /**
138
132
  * @typedef {String} ReleaseIdentifier The pre-release identifier without the last dynamic part (the pre-release sequential number).