@ckeditor/ckeditor5-dev-release-tools 32.0.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/LICENSE.md +16 -0
- package/README.md +89 -0
- package/lib/index.js +28 -0
- package/lib/tasks/bumpversions.js +354 -0
- package/lib/tasks/generatechangelogformonorepository.js +723 -0
- package/lib/tasks/generatechangelogforsinglepackage.js +202 -0
- package/lib/tasks/releasesubrepositories.js +929 -0
- package/lib/tasks/updateckeditor5dependencies.js +392 -0
- package/lib/templates/commit.hbs +29 -0
- package/lib/templates/footer.hbs +10 -0
- package/lib/templates/header.hbs +23 -0
- package/lib/templates/release-package.json +12 -0
- package/lib/templates/template.hbs +37 -0
- package/lib/utils/changelog.js +67 -0
- package/lib/utils/cli.js +324 -0
- package/lib/utils/creategithubrelease.js +35 -0
- package/lib/utils/displaycommits.js +105 -0
- package/lib/utils/displayskippedpackages.js +32 -0
- package/lib/utils/executeonpackages.js +26 -0
- package/lib/utils/generatechangelog.js +121 -0
- package/lib/utils/getchangedfilesforcommit.js +33 -0
- package/lib/utils/getcommits.js +104 -0
- package/lib/utils/getnewversiontype.js +53 -0
- package/lib/utils/getpackagejson.js +24 -0
- package/lib/utils/getpackagespaths.js +90 -0
- package/lib/utils/getpackagestorelease.js +152 -0
- package/lib/utils/getwriteroptions.js +33 -0
- package/lib/utils/parseroptions.js +26 -0
- package/lib/utils/transformcommitfactory.js +492 -0
- package/lib/utils/transformcommitutils.js +163 -0
- package/lib/utils/updatedependenciesversions.js +32 -0
- package/lib/utils/validatepackagetorelease.js +54 -0
- package/lib/utils/versions.js +59 -0
- package/package.json +52 -0
package/lib/utils/cli.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const inquirer = require( 'inquirer' );
|
|
9
|
+
const semver = require( 'semver' );
|
|
10
|
+
const chalk = require( 'chalk' );
|
|
11
|
+
|
|
12
|
+
const QUESTION_MARK = chalk.cyan( '?' );
|
|
13
|
+
|
|
14
|
+
const cli = {
|
|
15
|
+
/**
|
|
16
|
+
* A size of default indent for a log.
|
|
17
|
+
*/
|
|
18
|
+
INDENT_SIZE: 3,
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A size of indent for a second and next lines in a log. The number is equal to length of the log string:
|
|
22
|
+
* '* 1234567 ', where '1234567' is a short commit id.
|
|
23
|
+
* It does not include a value from `cli.INDENT_SIZE`.
|
|
24
|
+
*/
|
|
25
|
+
COMMIT_INDENT_SIZE: 10,
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Asks a user for a confirmation for updating and tagging versions of the packages.
|
|
29
|
+
*
|
|
30
|
+
* @param {Map} packages Packages to release.
|
|
31
|
+
* @returns {Promise.<Boolean>}
|
|
32
|
+
*/
|
|
33
|
+
confirmUpdatingVersions( packages ) {
|
|
34
|
+
let message = 'Packages and their old and new versions:\n';
|
|
35
|
+
|
|
36
|
+
for ( const packageName of Array.from( packages.keys() ).sort() ) {
|
|
37
|
+
const packageDetails = packages.get( packageName );
|
|
38
|
+
|
|
39
|
+
message += ` * "${ packageName }": v${ packageDetails.previousVersion } => v${ packageDetails.version }\n`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
message += 'Continue?';
|
|
43
|
+
|
|
44
|
+
const confirmQuestion = {
|
|
45
|
+
message,
|
|
46
|
+
type: 'confirm',
|
|
47
|
+
name: 'confirm',
|
|
48
|
+
default: true
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return inquirer.prompt( [ confirmQuestion ] )
|
|
52
|
+
.then( answers => answers.confirm );
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Asks a user for a confirmation for publishing changes.
|
|
57
|
+
*
|
|
58
|
+
* @param {Map} packages Packages to release.
|
|
59
|
+
* @returns {Promise.<Boolean>}
|
|
60
|
+
*/
|
|
61
|
+
confirmPublishing( packages ) {
|
|
62
|
+
let message = 'Services where the release will be created:\n';
|
|
63
|
+
|
|
64
|
+
for ( const packageName of Array.from( packages.keys() ).sort() ) {
|
|
65
|
+
const packageDetails = packages.get( packageName );
|
|
66
|
+
|
|
67
|
+
let packageMessage = ` * "${ packageName }" - version: ${ packageDetails.version }`;
|
|
68
|
+
|
|
69
|
+
const services = [];
|
|
70
|
+
|
|
71
|
+
if ( packageDetails.shouldReleaseOnNpm ) {
|
|
72
|
+
services.push( 'NPM' );
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if ( packageDetails.shouldReleaseOnGithub ) {
|
|
76
|
+
services.push( 'GitHub' );
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let color;
|
|
80
|
+
|
|
81
|
+
if ( services.length ) {
|
|
82
|
+
color = chalk.magenta;
|
|
83
|
+
packageMessage += ` - services: ${ services.join( ', ' ) } `;
|
|
84
|
+
} else {
|
|
85
|
+
color = chalk.gray;
|
|
86
|
+
packageMessage += ' - nothing to release';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
message += color( packageMessage ) + '\n';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
message += 'Continue?';
|
|
93
|
+
|
|
94
|
+
const confirmQuestion = {
|
|
95
|
+
message,
|
|
96
|
+
type: 'confirm',
|
|
97
|
+
name: 'confirm',
|
|
98
|
+
default: true
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return inquirer.prompt( [ confirmQuestion ] )
|
|
102
|
+
.then( answers => answers.confirm );
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Asks a user for a confirmation for removing archives created by `npm pack` command.
|
|
107
|
+
*
|
|
108
|
+
* @returns {Promise.<Boolean>}
|
|
109
|
+
*/
|
|
110
|
+
confirmRemovingFiles() {
|
|
111
|
+
const confirmQuestion = {
|
|
112
|
+
message: 'Remove created archives?',
|
|
113
|
+
type: 'confirm',
|
|
114
|
+
name: 'confirm',
|
|
115
|
+
default: true
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return inquirer.prompt( [ confirmQuestion ] )
|
|
119
|
+
.then( answers => answers.confirm );
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Asks a user for a confirmation for including a package that does not contain all required files.
|
|
124
|
+
*
|
|
125
|
+
* @returns {Promise.<Boolean>}
|
|
126
|
+
*/
|
|
127
|
+
confirmIncludingPackage() {
|
|
128
|
+
const confirmQuestion = {
|
|
129
|
+
message: 'Package does not contain all required files to publish. Include this package in the release and continue?',
|
|
130
|
+
type: 'confirm',
|
|
131
|
+
name: 'confirm',
|
|
132
|
+
default: true
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return inquirer.prompt( [ confirmQuestion ] )
|
|
136
|
+
.then( answers => answers.confirm );
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Asks a user for providing the new version.
|
|
141
|
+
*
|
|
142
|
+
* @param {String} packageVersion
|
|
143
|
+
* @param {String|null} releaseTypeOrNewVersion
|
|
144
|
+
* @param {Object} [options]
|
|
145
|
+
* @param {Boolean} [options.disableInternalVersion=false] Whether to "internal" version is enabled.
|
|
146
|
+
* @param {Boolean} [options.disableSkipVersion=false] Whether to "skip" version is enabled.
|
|
147
|
+
* @param {Number} [options.indentLevel=0] The indent level.
|
|
148
|
+
* @returns {Promise.<String>}
|
|
149
|
+
*/
|
|
150
|
+
provideVersion( packageVersion, releaseTypeOrNewVersion, options = {} ) {
|
|
151
|
+
const indentLevel = options.indentLevel || 0;
|
|
152
|
+
const suggestedVersion = getSuggestedVersion();
|
|
153
|
+
|
|
154
|
+
let message = 'Type the new version, "skip" or "internal"';
|
|
155
|
+
|
|
156
|
+
if ( options.disableInternalVersion ) {
|
|
157
|
+
message = 'Type the new version or "skip"';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
message += ` (suggested: "${ suggestedVersion }", current: "${ packageVersion }"):`;
|
|
161
|
+
|
|
162
|
+
const versionQuestion = {
|
|
163
|
+
type: 'input',
|
|
164
|
+
name: 'version',
|
|
165
|
+
default: suggestedVersion,
|
|
166
|
+
message,
|
|
167
|
+
|
|
168
|
+
filter( input ) {
|
|
169
|
+
return input.trim();
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
validate( input ) {
|
|
173
|
+
if ( !options.disableSkipVersion && input === 'skip' ) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if ( !options.disableInternalVersion && input === 'internal' ) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// TODO: Check whether provided version is available.
|
|
182
|
+
return semver.valid( input ) ? true : 'Please provide a valid version.';
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
prefix: getPrefix( indentLevel )
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return inquirer.prompt( [ versionQuestion ] )
|
|
189
|
+
.then( answers => answers.version );
|
|
190
|
+
|
|
191
|
+
function getSuggestedVersion() {
|
|
192
|
+
if ( !releaseTypeOrNewVersion || releaseTypeOrNewVersion === 'skip' ) {
|
|
193
|
+
return 'skip';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if ( semver.valid( releaseTypeOrNewVersion ) ) {
|
|
197
|
+
return releaseTypeOrNewVersion;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if ( releaseTypeOrNewVersion === 'internal' ) {
|
|
201
|
+
return options.disableInternalVersion ? 'skip' : 'internal';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if ( semver.prerelease( packageVersion ) ) {
|
|
205
|
+
releaseTypeOrNewVersion = 'prerelease';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// If package's version is below the '1.0.0', bump the 'minor' instead of 'major'
|
|
209
|
+
if ( releaseTypeOrNewVersion === 'major' && semver.gt( '1.0.0', packageVersion ) ) {
|
|
210
|
+
return semver.inc( packageVersion, 'minor' );
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return semver.inc( packageVersion, releaseTypeOrNewVersion );
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Asks a user for providing the new version for a major release.
|
|
219
|
+
*
|
|
220
|
+
* @param {String} version
|
|
221
|
+
* @param {String} foundPackage
|
|
222
|
+
* @param {String} bumpType
|
|
223
|
+
* @param {Object} [options={}]
|
|
224
|
+
* @param {Number} [options.indentLevel=0] The indent level.
|
|
225
|
+
* @returns {Promise.<String>}
|
|
226
|
+
*/
|
|
227
|
+
provideNewVersionForMonoRepository( version, foundPackage, bumpType, options = {} ) {
|
|
228
|
+
const indentLevel = options.indentLevel || 0;
|
|
229
|
+
const suggestedVersion = semver.inc( version, bumpType );
|
|
230
|
+
|
|
231
|
+
const message = 'Type the new version ' +
|
|
232
|
+
`(current highest: "${ version }" found in "${ chalk.underline( foundPackage ) }", suggested: "${ suggestedVersion }"):`;
|
|
233
|
+
|
|
234
|
+
const versionQuestion = {
|
|
235
|
+
type: 'input',
|
|
236
|
+
name: 'version',
|
|
237
|
+
default: suggestedVersion,
|
|
238
|
+
message,
|
|
239
|
+
|
|
240
|
+
filter( input ) {
|
|
241
|
+
return input.trim();
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
validate( input ) {
|
|
245
|
+
if ( !semver.valid( input ) ) {
|
|
246
|
+
return 'Please provide a valid version.';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return semver.gt( input, version ) ? true : `Provided version must be higher than "${ version }".`;
|
|
250
|
+
},
|
|
251
|
+
prefix: getPrefix( indentLevel )
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
return inquirer.prompt( [ versionQuestion ] )
|
|
255
|
+
.then( answers => answers.version );
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Asks a user for providing the GitHub token.
|
|
260
|
+
*
|
|
261
|
+
* @returns {Promise.<String>}
|
|
262
|
+
*/
|
|
263
|
+
provideToken() {
|
|
264
|
+
const tokenQuestion = {
|
|
265
|
+
type: 'password',
|
|
266
|
+
name: 'token',
|
|
267
|
+
message: 'Provide the GitHub token:',
|
|
268
|
+
validate( input ) {
|
|
269
|
+
return input.length === 40 ? true : 'Please provide a valid token.';
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
return inquirer.prompt( [ tokenQuestion ] )
|
|
274
|
+
.then( answers => answers.token );
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Asks a user for selecting services where packages will be released.
|
|
279
|
+
*
|
|
280
|
+
* If the user choices a GitHub, required token also has to be provided.
|
|
281
|
+
*
|
|
282
|
+
* @returns {Promise.<Object>}
|
|
283
|
+
*/
|
|
284
|
+
configureReleaseOptions() {
|
|
285
|
+
const options = {};
|
|
286
|
+
|
|
287
|
+
const servicesQuestion = {
|
|
288
|
+
type: 'checkbox',
|
|
289
|
+
name: 'services',
|
|
290
|
+
message: 'Select services where packages will be released:',
|
|
291
|
+
choices: [
|
|
292
|
+
'npm',
|
|
293
|
+
'GitHub'
|
|
294
|
+
],
|
|
295
|
+
default: [
|
|
296
|
+
'npm',
|
|
297
|
+
'GitHub'
|
|
298
|
+
]
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
return inquirer.prompt( [ servicesQuestion ] )
|
|
302
|
+
.then( answers => {
|
|
303
|
+
options.npm = answers.services.includes( 'npm' );
|
|
304
|
+
options.github = answers.services.includes( 'GitHub' );
|
|
305
|
+
|
|
306
|
+
if ( !options.github ) {
|
|
307
|
+
return options;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return cli.provideToken()
|
|
311
|
+
.then( token => {
|
|
312
|
+
options.token = token;
|
|
313
|
+
|
|
314
|
+
return options;
|
|
315
|
+
} );
|
|
316
|
+
} );
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
module.exports = cli;
|
|
321
|
+
|
|
322
|
+
function getPrefix( indent ) {
|
|
323
|
+
return ' '.repeat( indent * cli.INDENT_SIZE ) + QUESTION_MARK;
|
|
324
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const { Octokit } = require( '@octokit/rest' );
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a Github release.
|
|
12
|
+
*
|
|
13
|
+
* @param {String} token Token used to authenticate with GitHub.
|
|
14
|
+
* @param {Object} options
|
|
15
|
+
* @param {String} options.repositoryOwner Owner of the repository.
|
|
16
|
+
* @param {String} options.repositoryName Repository name.
|
|
17
|
+
* @param {String} options.version Name of tag connected with the release.
|
|
18
|
+
* @param {String} options.description Description of the release.
|
|
19
|
+
* @returns {Promise}
|
|
20
|
+
*/
|
|
21
|
+
module.exports = function createGithubRelease( token, options ) {
|
|
22
|
+
const github = new Octokit( {
|
|
23
|
+
version: '3.0.0',
|
|
24
|
+
auth: `token ${ token }`
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
const releaseParams = {
|
|
28
|
+
owner: options.repositoryOwner,
|
|
29
|
+
repo: options.repositoryName,
|
|
30
|
+
tag_name: options.version,
|
|
31
|
+
body: options.description
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return github.repos.createRelease( releaseParams );
|
|
35
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const chalk = require( 'chalk' );
|
|
9
|
+
const { logger } = require( '@ckeditor/ckeditor5-dev-utils' );
|
|
10
|
+
const utils = require( './transformcommitutils' );
|
|
11
|
+
const { INDENT_SIZE, COMMIT_INDENT_SIZE } = require( './cli' );
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Array.<Commit>|Set.<Commit>} commits
|
|
15
|
+
* @param {Object} [options={}]
|
|
16
|
+
* @param {Boolean} [options.attachLinkToCommit=false] Whether to attach a link to parsed commit.
|
|
17
|
+
* @param {Number} [options.indentLevel=1] The indent level.
|
|
18
|
+
*/
|
|
19
|
+
module.exports = function displayCommits( commits, options = {} ) {
|
|
20
|
+
const log = logger();
|
|
21
|
+
|
|
22
|
+
const attachLinkToCommit = options.attachLinkToCommit || false;
|
|
23
|
+
const indentLevel = options.indentLevel || 1;
|
|
24
|
+
const listIndent = ' '.repeat( INDENT_SIZE * indentLevel );
|
|
25
|
+
|
|
26
|
+
if ( !( commits.length || commits.size ) ) {
|
|
27
|
+
log.info( listIndent + chalk.italic( 'No commits to display.' ) );
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const COMMITS_SEPARATOR = listIndent + chalk.gray( '-'.repeat( 112 ) );
|
|
31
|
+
|
|
32
|
+
// Group of commits by the commit's hash.
|
|
33
|
+
/** @type {Map.<String, Set.<Commit>>} */
|
|
34
|
+
const commitGroups = new Map();
|
|
35
|
+
|
|
36
|
+
for ( const singleCommit of commits ) {
|
|
37
|
+
getCommitGroup( singleCommit ).add( singleCommit );
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A flag that helps avoid duplication separators if two groups are consecutive one after another.
|
|
41
|
+
let finishedWithSeparator = false;
|
|
42
|
+
|
|
43
|
+
for ( const [ hash, commits ] of commitGroups ) {
|
|
44
|
+
// Do not duplicate the separator if it was already added.
|
|
45
|
+
if ( commits.size > 1 && !finishedWithSeparator ) {
|
|
46
|
+
log.info( COMMITS_SEPARATOR );
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for ( const singleCommit of commits.values() ) {
|
|
50
|
+
const hasCorrectType = utils.availableCommitTypes.has( singleCommit.rawType );
|
|
51
|
+
const isCommitIncluded = utils.availableCommitTypes.get( singleCommit.rawType );
|
|
52
|
+
|
|
53
|
+
const indent = commits.size > 1 ? listIndent.slice( 0, listIndent.length - 1 ) + chalk.gray( '|' ) : listIndent;
|
|
54
|
+
const noteIndent = indent + ' '.repeat( COMMIT_INDENT_SIZE );
|
|
55
|
+
|
|
56
|
+
let logMessage = `${ indent }* ${ chalk.yellow( hash.slice( 0, 7 ) ) } "${ utils.truncate( singleCommit.header, 100 ) }" `;
|
|
57
|
+
|
|
58
|
+
if ( hasCorrectType && isCommitIncluded ) {
|
|
59
|
+
logMessage += chalk.green( 'INCLUDED' );
|
|
60
|
+
} else if ( hasCorrectType && !isCommitIncluded ) {
|
|
61
|
+
logMessage += chalk.grey( 'SKIPPED' );
|
|
62
|
+
} else {
|
|
63
|
+
logMessage += chalk.red( 'INVALID' );
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Avoid displaying singleCommit merge twice.
|
|
67
|
+
if ( singleCommit.merge && singleCommit.merge !== singleCommit.header ) {
|
|
68
|
+
logMessage += `\n${ noteIndent }${ chalk.italic( singleCommit.merge ) }`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for ( const note of singleCommit.notes ) {
|
|
72
|
+
const limit = 100 - note.title.length;
|
|
73
|
+
|
|
74
|
+
logMessage += `\n${ noteIndent }${ note.title }: ${ utils.truncate( note.text, limit ) } `;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ( attachLinkToCommit ) {
|
|
78
|
+
const url = `${ singleCommit.repositoryUrl }/commit/${ singleCommit.hash }`;
|
|
79
|
+
|
|
80
|
+
logMessage += `\n${ noteIndent }${ chalk.gray( url ) }`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
log.info( logMessage );
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if ( commits.size > 1 ) {
|
|
87
|
+
finishedWithSeparator = true;
|
|
88
|
+
log.info( COMMITS_SEPARATOR );
|
|
89
|
+
} else {
|
|
90
|
+
finishedWithSeparator = false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {Commit} commit
|
|
96
|
+
* @returns {Set.<Commit>}
|
|
97
|
+
*/
|
|
98
|
+
function getCommitGroup( commit ) {
|
|
99
|
+
if ( !commitGroups.has( commit.hash ) ) {
|
|
100
|
+
commitGroups.set( commit.hash, new Set() );
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return commitGroups.get( commit.hash );
|
|
104
|
+
}
|
|
105
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const chalk = require( 'chalk' );
|
|
9
|
+
const { logger } = require( '@ckeditor/ckeditor5-dev-utils' );
|
|
10
|
+
const getPackageJson = require( './getpackagejson' );
|
|
11
|
+
const { INDENT_SIZE } = require( './cli' );
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Displays skipped packages.
|
|
15
|
+
*
|
|
16
|
+
* @param {Set} skippedPackagesPaths
|
|
17
|
+
*/
|
|
18
|
+
module.exports = function displaySkippedPackages( skippedPackagesPaths ) {
|
|
19
|
+
if ( !skippedPackagesPaths.size ) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const indent = ' '.repeat( INDENT_SIZE );
|
|
24
|
+
|
|
25
|
+
const packageNames = Array.from( skippedPackagesPaths )
|
|
26
|
+
.map( packagePath => getPackageJson( packagePath ).name );
|
|
27
|
+
|
|
28
|
+
let message = indent + chalk.bold.underline( 'Packages listed below have been skipped:' ) + '\n';
|
|
29
|
+
message += packageNames.map( line => indent + ` * ${ line }` ).join( '\n' );
|
|
30
|
+
|
|
31
|
+
logger().info( message );
|
|
32
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The function allows running a function on locally installed packages.
|
|
10
|
+
*
|
|
11
|
+
* @param {Iterable} pathsToPackages A collection of paths to packages.
|
|
12
|
+
* @param {Function} functionToExecute A function that will be called on each package.
|
|
13
|
+
* The function receives one argument:
|
|
14
|
+
* * `{String} dependencyPath An absolute path to the package.`
|
|
15
|
+
* The function should return a promise.
|
|
16
|
+
* @returns {Promise}
|
|
17
|
+
*/
|
|
18
|
+
module.exports = function executeOnPackages( pathsToPackages, functionToExecute ) {
|
|
19
|
+
let promise = Promise.resolve();
|
|
20
|
+
|
|
21
|
+
for ( const pathToSinglePackage of pathsToPackages ) {
|
|
22
|
+
promise = promise.then( () => functionToExecute( pathToSinglePackage ) );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return promise;
|
|
26
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const { Readable } = require( 'stream' );
|
|
9
|
+
const { stream } = require( '@ckeditor/ckeditor5-dev-utils' );
|
|
10
|
+
const conventionalChangelogWriter = require( 'conventional-changelog-writer' );
|
|
11
|
+
|
|
12
|
+
const UPDATED_TRANSLATION_COMMIT = '* Updated translations.';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generates the changelog based on commits.
|
|
16
|
+
*
|
|
17
|
+
* @param {Array.<Commit>} commits
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} context
|
|
20
|
+
* @param {String} context.version Current version for the release.
|
|
21
|
+
* @param {String} context.repoUrl The repository URL.
|
|
22
|
+
* @param {String} context.currentTag A tag for the current version.
|
|
23
|
+
* @param {String} context.commit Commit keyword in the URL.
|
|
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
|
+
* @param {Boolean} [context.skipCommitsLink=false] Whether to skip adding links to commit.
|
|
28
|
+
* @param {Boolean} [context.skipCompareLink=false] Whether to remove the compare URL in the header.
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} options
|
|
31
|
+
* @param {Object} options.transform
|
|
32
|
+
* @param {Function} options.transform.hash A function for mapping the commit's hash.
|
|
33
|
+
* @param {Array.<String>|String} options.groupBy A key for grouping the commits.
|
|
34
|
+
* @param {Function} options.commitGroupsSort A sort function for the groups.
|
|
35
|
+
* @param {Function} options.noteGroupsSort A soft function for the notes.
|
|
36
|
+
* @param {String} options.mainTemplate The main template for the changelog.
|
|
37
|
+
* @param {String} options.headerPartial The "header" partial used in the main template.
|
|
38
|
+
* @param {String} options.commitPartial The "commit" partial used in the main template.
|
|
39
|
+
* @param {String} options.footerPartial The "footer" partial used in the main template.
|
|
40
|
+
*
|
|
41
|
+
* @returns {Promise.<String>}
|
|
42
|
+
*/
|
|
43
|
+
module.exports = function generateChangelog( commits, context, options ) {
|
|
44
|
+
const commitStream = new Readable( { objectMode: true } );
|
|
45
|
+
/* istanbul ignore next */
|
|
46
|
+
commitStream._read = function() {};
|
|
47
|
+
|
|
48
|
+
for ( const commitItem of commits ) {
|
|
49
|
+
commitStream.push( commitItem );
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
commitStream.push( null );
|
|
53
|
+
|
|
54
|
+
return new Promise( ( resolve, reject ) => {
|
|
55
|
+
commitStream
|
|
56
|
+
.pipe( conventionalChangelogWriter( context, options ) )
|
|
57
|
+
.pipe( stream.noop( changes => {
|
|
58
|
+
changes = mergeUpdateTranslationsCommits( changes.toString(), {
|
|
59
|
+
skipCommitsLink: context.skipCommitsLink
|
|
60
|
+
} );
|
|
61
|
+
|
|
62
|
+
resolve( changes );
|
|
63
|
+
} ) )
|
|
64
|
+
.on( 'error', reject );
|
|
65
|
+
} );
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Merges multiple "Updated translations." entries into the single commit.
|
|
70
|
+
*
|
|
71
|
+
* @param {String} changelog Generated changelog.
|
|
72
|
+
* @param {Object} [options={}]
|
|
73
|
+
* @param {Boolean} [options.skipCommitsLink=false] Whether to skip adding links to commit.
|
|
74
|
+
* @returns {String}
|
|
75
|
+
*/
|
|
76
|
+
function mergeUpdateTranslationsCommits( changelog, options = {} ) {
|
|
77
|
+
let foundUpdatedTranslationCommit = false;
|
|
78
|
+
|
|
79
|
+
const changelogAsArray = changelog.split( '\n' );
|
|
80
|
+
|
|
81
|
+
// An array that contains duplicated commits.
|
|
82
|
+
const removedEntries = [];
|
|
83
|
+
|
|
84
|
+
// An array that contains changelog without duplicated entries.
|
|
85
|
+
const uniqueEntries = changelogAsArray.filter( line => {
|
|
86
|
+
if ( !line.startsWith( UPDATED_TRANSLATION_COMMIT ) ) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if ( foundUpdatedTranslationCommit ) {
|
|
91
|
+
removedEntries.push( line );
|
|
92
|
+
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
foundUpdatedTranslationCommit = true;
|
|
97
|
+
|
|
98
|
+
return true;
|
|
99
|
+
} );
|
|
100
|
+
|
|
101
|
+
if ( options.skipCommitsLink ) {
|
|
102
|
+
return uniqueEntries.join( '\n' );
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return uniqueEntries.map( line => {
|
|
106
|
+
if ( !line.startsWith( UPDATED_TRANSLATION_COMMIT ) ) {
|
|
107
|
+
return line;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const newLine = line + ' ' + removedEntries
|
|
111
|
+
.map( entry => {
|
|
112
|
+
const match = entry.match( /(\(\[commit\].*)$/ );
|
|
113
|
+
|
|
114
|
+
return match ? match[ 1 ] : null;
|
|
115
|
+
} )
|
|
116
|
+
.filter( item => !!item )
|
|
117
|
+
.join( ' ' );
|
|
118
|
+
|
|
119
|
+
return newLine.trim().replace( /\) \(/g, ', ' );
|
|
120
|
+
} ).join( '\n' );
|
|
121
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2022, 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
|
+
* Returns an array with paths to changed files for given commit.
|
|
12
|
+
*
|
|
13
|
+
* @param {String} commitId
|
|
14
|
+
* @returns {Array.<String>}
|
|
15
|
+
*/
|
|
16
|
+
module.exports = function getChangedFilesForCommit( commitId ) {
|
|
17
|
+
const gitCommand = `git log -m -1 --name-only --pretty="format:" ${ commitId }`;
|
|
18
|
+
const changedFiles = tools.shExec( gitCommand, { verbosity: 'error' } ).trim();
|
|
19
|
+
|
|
20
|
+
// Merge commits can have two parents. Returned files for merge commits looks like:
|
|
21
|
+
// file1 <-- files from merged branch
|
|
22
|
+
// file2 <-- files from merged branch
|
|
23
|
+
// file <-- files from merged branch
|
|
24
|
+
//
|
|
25
|
+
// other-file1 <-- files from last commit before merge
|
|
26
|
+
// other-file2 <-- files from last commit before merge
|
|
27
|
+
// We need to filter out files from commit before merge.
|
|
28
|
+
|
|
29
|
+
return changedFiles.split( '\n\n' )[ 0 ]
|
|
30
|
+
.split( '\n' )
|
|
31
|
+
.map( file => file.trim() )
|
|
32
|
+
.filter( item => item );
|
|
33
|
+
};
|