@ckeditor/ckeditor5-dev-release-tools 37.0.1 → 38.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/lib/index.js +22 -10
- package/lib/tasks/cleanuppackages.js +175 -0
- package/lib/tasks/commitandtag.js +28 -0
- package/lib/tasks/creategithubrelease.js +106 -0
- package/lib/tasks/generatechangelogformonorepository.js +3 -0
- package/lib/tasks/preparerepository.js +149 -0
- package/lib/tasks/publishpackages.js +69 -0
- package/lib/tasks/push.js +29 -0
- package/lib/tasks/reassignnpmtags.js +93 -0
- package/lib/tasks/updatedependencies.js +84 -0
- package/lib/tasks/updateversions.js +117 -0
- package/lib/utils/assertfilestopublish.js +88 -0
- package/lib/utils/assertnpmauthorization.js +26 -0
- package/lib/utils/assertnpmtag.js +60 -0
- package/lib/utils/assertpackages.js +34 -0
- package/lib/utils/changelog.js +34 -0
- package/lib/utils/executeinparallel.js +167 -0
- package/lib/utils/getpackagejson.js +8 -4
- package/lib/utils/parallelworker.js +25 -0
- package/lib/utils/publishpackagesonnpm.js +35 -0
- package/lib/utils/{validatepackagetorelease.js → validaterepositorytorelease.js} +17 -12
- package/package.json +7 -14
- package/lib/tasks/bumpversions.js +0 -354
- package/lib/tasks/preparepackages.js +0 -257
- package/lib/tasks/releasesubrepositories.js +0 -1001
- package/lib/tasks/updateckeditor5dependencies.js +0 -392
- package/lib/utils/creategithubrelease.js +0 -37
- package/lib/utils/executeonpackages.js +0 -26
- package/lib/utils/getpackagestorelease.js +0 -152
- package/lib/utils/updatedependenciesversions.js +0 -32
|
@@ -1,354 +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 path = require( 'path' );
|
|
9
|
-
const chalk = require( 'chalk' );
|
|
10
|
-
const { tools, logger } = require( '@ckeditor/ckeditor5-dev-utils' );
|
|
11
|
-
const cli = require( '../utils/cli' );
|
|
12
|
-
const versions = require( '../utils/versions' );
|
|
13
|
-
const changelog = require( '../utils/changelog' );
|
|
14
|
-
const displaySkippedPackages = require( '../utils/displayskippedpackages' );
|
|
15
|
-
const executeOnPackages = require( '../utils/executeonpackages' );
|
|
16
|
-
const getPackageJson = require( '../utils/getpackagejson' );
|
|
17
|
-
const getPackagesToRelease = require( '../utils/getpackagestorelease' );
|
|
18
|
-
const getPackagesPaths = require( '../utils/getpackagespaths' );
|
|
19
|
-
const updateDependenciesVersions = require( '../utils/updatedependenciesversions' );
|
|
20
|
-
const validatePackageToRelease = require( '../utils/validatepackagetorelease' );
|
|
21
|
-
|
|
22
|
-
const BREAK_RELEASE_MESSAGE = 'You aborted updating versions. Why? Oh why?!';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Updates version of all subpackages found in specified path.
|
|
26
|
-
*
|
|
27
|
-
* This task does:
|
|
28
|
-
* - finds paths to subpackages,
|
|
29
|
-
* - updates versions of all dependencies (even if some packages will not be released, its version will be updated in released packages),
|
|
30
|
-
* - bumps version of all packages.
|
|
31
|
-
*
|
|
32
|
-
* @param {String} options.cwd Current working directory (packages) from which all paths will be resolved.
|
|
33
|
-
* @param {String|null} options.packages Where to look for other packages (dependencies). If `null`, only repository specified under
|
|
34
|
-
* `options.cwd` will be used in the task.
|
|
35
|
-
* @param {Array.<String>} [options.skipPackages=[]] Name of packages which won't be touched.
|
|
36
|
-
* @param {Boolean} [options.dryRun=false] If set on true, all changes will be printed on the screen. Changes produced by commands like
|
|
37
|
-
* `npm version` will be reverted. Every called command will be displayed.
|
|
38
|
-
* @param {Boolean} [options.skipMainRepository=false] If set on true, package found in "cwd" will be skipped.
|
|
39
|
-
* @param {String} [options.releaseBranch='master'] A name of the branch that should be used for releasing packages.
|
|
40
|
-
* @param {String} [options.changelogDirectory] An absolute path to the directory where the `CHANGELOG.md` file is saved. If not specified,
|
|
41
|
-
* the `options.cwd` value will be used instead.
|
|
42
|
-
* @param {Boolean} [options.skipUpdatingDependencies=false] Whether to skip updating version of dependencies between updated packages.
|
|
43
|
-
* @returns {Promise} A collection with packages that were updated.
|
|
44
|
-
*/
|
|
45
|
-
module.exports = async function bumpVersions( options ) {
|
|
46
|
-
const cwd = process.cwd();
|
|
47
|
-
const log = logger();
|
|
48
|
-
|
|
49
|
-
const dryRun = Boolean( options.dryRun );
|
|
50
|
-
|
|
51
|
-
const pathsCollection = getPackagesPaths( {
|
|
52
|
-
cwd: options.cwd,
|
|
53
|
-
packages: options.packages,
|
|
54
|
-
skipPackages: options.skipPackages || [],
|
|
55
|
-
skipMainRepository: options.skipMainRepository
|
|
56
|
-
} );
|
|
57
|
-
|
|
58
|
-
const changelogDirectory = options.changelogDirectory || options.cwd;
|
|
59
|
-
|
|
60
|
-
const mainRepositoryVersion = versions.getLastFromChangelog( changelogDirectory );
|
|
61
|
-
const mainChangelog = changelog.getChangesForVersion( mainRepositoryVersion, changelogDirectory );
|
|
62
|
-
const releaseBranch = options.releaseBranch || 'master';
|
|
63
|
-
|
|
64
|
-
logDryRun( '⚠️ DRY RUN mode ⚠️' );
|
|
65
|
-
logDryRun( 'All changes made by this script will be reverted automatically.' );
|
|
66
|
-
logProcess( 'Collecting packages which versions should be updated...' );
|
|
67
|
-
|
|
68
|
-
// In order to avoid setting global variables, every function passes `packages` variable to another function.
|
|
69
|
-
|
|
70
|
-
return getPackagesToRelease( pathsCollection.matched, { changes: mainChangelog, version: mainRepositoryVersion } )
|
|
71
|
-
.then( packages => isAnythingForRelease( packages ) )
|
|
72
|
-
.then( packages => confirmUpdate( packages ) )
|
|
73
|
-
.then( packages => prepareDependenciesVersions( packages ) )
|
|
74
|
-
.then( ( { packages, dependencies } ) => filterPackagesThatWillNotBeReleased( packages, dependencies ) )
|
|
75
|
-
.then( ( { packages, dependencies } ) => updateDependenciesOfPackages( packages, dependencies ) )
|
|
76
|
-
.then( packages => updateLatestChangesForMainRepository( packages, mainRepositoryVersion ) )
|
|
77
|
-
.then( packages => validateRepository( packages ) )
|
|
78
|
-
.then( packages => bumpVersion( packages ) )
|
|
79
|
-
.then( () => {
|
|
80
|
-
process.chdir( cwd );
|
|
81
|
-
|
|
82
|
-
logProcess( `Finished updating versions of ${ chalk.underline( pathsCollection.matched.size ) } package(s).` );
|
|
83
|
-
logDryRun( 'Because of the DRY RUN mode, nothing has been changed. All changes were reverted.' );
|
|
84
|
-
|
|
85
|
-
return Promise.resolve( pathsCollection.matched );
|
|
86
|
-
} )
|
|
87
|
-
.catch( err => {
|
|
88
|
-
process.chdir( cwd );
|
|
89
|
-
|
|
90
|
-
// A user did not confirm the release process.
|
|
91
|
-
if ( err instanceof Error && err.message === BREAK_RELEASE_MESSAGE ) {
|
|
92
|
-
logProcess( 'Updating has been aborted.' );
|
|
93
|
-
|
|
94
|
-
return Promise.resolve();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
log.error( err.message );
|
|
98
|
-
|
|
99
|
-
process.exitCode = -1;
|
|
100
|
-
} );
|
|
101
|
-
|
|
102
|
-
// Displays packages that won't match to specified criteria and checks whether there is at least one package
|
|
103
|
-
// that should update its version.
|
|
104
|
-
//
|
|
105
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
106
|
-
// @returns {Map.<String, ReleaseDetails>}
|
|
107
|
-
function isAnythingForRelease( packages ) {
|
|
108
|
-
logProcess( 'Checking whether is there anything for updating...' );
|
|
109
|
-
|
|
110
|
-
displaySkippedPackages( pathsCollection.skipped );
|
|
111
|
-
|
|
112
|
-
if ( packages.size === 0 ) {
|
|
113
|
-
throw new Error( 'None of the packages contains any changes since its last release. Aborting.' );
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return packages;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Asks a user whether the process should be continued.
|
|
120
|
-
//
|
|
121
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
122
|
-
// @returns {Promise.<Map.<String, ReleaseDetails>>}
|
|
123
|
-
function confirmUpdate( packages ) {
|
|
124
|
-
logProcess( 'Should we continue?' );
|
|
125
|
-
|
|
126
|
-
return cli.confirmUpdatingVersions( packages )
|
|
127
|
-
.then( isConfirmed => {
|
|
128
|
-
if ( !isConfirmed ) {
|
|
129
|
-
throw new Error( BREAK_RELEASE_MESSAGE );
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return packages;
|
|
133
|
-
} );
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Prepare a map that contains new versions of packages. It will be used for updating dependencies' version during the release.
|
|
137
|
-
//
|
|
138
|
-
// This map contains new versions of all packages that will be released and current version of all packages which won't match to
|
|
139
|
-
// specified criteria or won't be released (no changes between current and previous release).
|
|
140
|
-
//
|
|
141
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
142
|
-
// @returns {Object}
|
|
143
|
-
function prepareDependenciesVersions( packages ) {
|
|
144
|
-
logProcess( 'Preparing to updating versions of dependencies...' );
|
|
145
|
-
|
|
146
|
-
const dependencies = new Map();
|
|
147
|
-
|
|
148
|
-
// For every package that will be released, save its name and the latest version.
|
|
149
|
-
for ( const [ packageName, { version } ] of packages ) {
|
|
150
|
-
dependencies.set( packageName, version );
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Packages which won't match to specified criteria won't be released but we want to update their
|
|
154
|
-
// versions in packages where skipped packages are defined as dependencies.
|
|
155
|
-
for ( const packagePath of pathsCollection.skipped ) {
|
|
156
|
-
const packageJson = getPackageJson( packagePath );
|
|
157
|
-
|
|
158
|
-
dependencies.set( packageJson.name, packageJson.version );
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Even if some packages match to specified criteria but won't be releases because of no changes,
|
|
162
|
-
// we want to update their version in packages where they are defined as dependency.
|
|
163
|
-
for ( const packagePath of pathsCollection.matched ) {
|
|
164
|
-
const packageJson = getPackageJson( packagePath );
|
|
165
|
-
|
|
166
|
-
if ( !dependencies.has( packageJson.name ) ) {
|
|
167
|
-
dependencies.set( packageJson.name, packageJson.version );
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return { packages, dependencies };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Filter out packages which won't be released.
|
|
175
|
-
//
|
|
176
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
177
|
-
// @params {Map} dependencies
|
|
178
|
-
// @returns {Object}
|
|
179
|
-
function filterPackagesThatWillNotBeReleased( packages, dependencies ) {
|
|
180
|
-
logDryRun( 'Filtering out packages that will not be updated...' );
|
|
181
|
-
|
|
182
|
-
for ( const pathToPackage of pathsCollection.matched ) {
|
|
183
|
-
const packageName = getPackageJson( pathToPackage ).name;
|
|
184
|
-
|
|
185
|
-
if ( !packages.has( packageName ) ) {
|
|
186
|
-
pathsCollection.matched.delete( pathToPackage );
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return { packages, dependencies };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Update versions of all dependencies.
|
|
194
|
-
//
|
|
195
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
196
|
-
// @params {Map} dependencies
|
|
197
|
-
// @returns {Promise.<Map.<String, ReleaseDetails>>}
|
|
198
|
-
function updateDependenciesOfPackages( packages, dependencies ) {
|
|
199
|
-
if ( options.skipUpdatingDependencies ) {
|
|
200
|
-
logProcess( 'Skipping updating dependencies...' );
|
|
201
|
-
|
|
202
|
-
return Promise.resolve( packages );
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
logProcess( 'Updating dependencies for packages that will be released...' );
|
|
206
|
-
let hasUpdatedAnyPackage = false;
|
|
207
|
-
|
|
208
|
-
return executeOnPackages( pathsCollection.matched, repositoryPath => {
|
|
209
|
-
process.chdir( repositoryPath );
|
|
210
|
-
|
|
211
|
-
const packageJson = getPackageJson( repositoryPath );
|
|
212
|
-
|
|
213
|
-
log.info( `\nUpdating dependencies for "${ chalk.underline( packageJson.name ) }"...` );
|
|
214
|
-
|
|
215
|
-
updateDependenciesVersions( dependencies, path.join( repositoryPath, 'package.json' ) );
|
|
216
|
-
|
|
217
|
-
if ( exec( 'git diff --name-only package.json' ).trim().length ) {
|
|
218
|
-
if ( dryRun ) {
|
|
219
|
-
logDryRun( 'These changes would be committed.' );
|
|
220
|
-
|
|
221
|
-
log.info( chalk.grey( exec( 'git diff --word-diff package.json' ) ) );
|
|
222
|
-
exec( 'git checkout package.json' );
|
|
223
|
-
} else {
|
|
224
|
-
hasUpdatedAnyPackage = true;
|
|
225
|
-
|
|
226
|
-
exec( 'git add package.json' );
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return Promise.resolve();
|
|
231
|
-
} ).then( () => {
|
|
232
|
-
process.chdir( cwd );
|
|
233
|
-
|
|
234
|
-
if ( hasUpdatedAnyPackage ) {
|
|
235
|
-
exec( 'git commit -m "Internal: Updated dependencies. [skip ci]"' );
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return packages;
|
|
239
|
-
} );
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Gather descriptions of the release for all packages.
|
|
243
|
-
//
|
|
244
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
245
|
-
// @returns {<Map.<String, ReleaseDetails>}
|
|
246
|
-
function updateLatestChangesForMainRepository( packages, changes ) {
|
|
247
|
-
logProcess( 'Updating changes for the main repository...' );
|
|
248
|
-
|
|
249
|
-
const packageJson = getPackageJson( options.cwd );
|
|
250
|
-
const releaseDetails = packages.get( packageJson.name );
|
|
251
|
-
|
|
252
|
-
releaseDetails.changes = changes;
|
|
253
|
-
|
|
254
|
-
return packages;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Validate the main repository.
|
|
258
|
-
//
|
|
259
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
260
|
-
// @returns {Map.<String, ReleaseDetails>}
|
|
261
|
-
function validateRepository( packages ) {
|
|
262
|
-
logProcess( 'Validating the main repository...' );
|
|
263
|
-
|
|
264
|
-
const mainPackageJson = getPackageJson( options.cwd );
|
|
265
|
-
const releaseDetails = packages.get( mainPackageJson.name );
|
|
266
|
-
|
|
267
|
-
const errors = validatePackageToRelease( {
|
|
268
|
-
branch: releaseBranch,
|
|
269
|
-
changes: releaseDetails.changes,
|
|
270
|
-
version: releaseDetails.version
|
|
271
|
-
} );
|
|
272
|
-
|
|
273
|
-
if ( errors.length ) {
|
|
274
|
-
log.error( `‼️ ${ chalk.underline( mainPackageJson.name ) }` );
|
|
275
|
-
errors.forEach( err => {
|
|
276
|
-
log.error( '* ' + err );
|
|
277
|
-
} );
|
|
278
|
-
|
|
279
|
-
throw new Error( 'Updating has been aborted due to errors.' );
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return packages;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Updates versions of packages.
|
|
286
|
-
//
|
|
287
|
-
// @params {Map.<String, ReleaseDetails>} packages
|
|
288
|
-
// @returns {Promise.<Map.<String, ReleaseDetails>>}
|
|
289
|
-
function bumpVersion( packages ) {
|
|
290
|
-
logProcess( 'Tagging new versions of packages...' );
|
|
291
|
-
|
|
292
|
-
let numberOfCommitsBeforeVersioning;
|
|
293
|
-
|
|
294
|
-
// Based on number of commits before and after executing `npm version`, we will be able to revert all changes
|
|
295
|
-
// that have been done. It allows reverting changes done by npm `preversion` and/or `postversion` hooks.
|
|
296
|
-
if ( dryRun ) {
|
|
297
|
-
numberOfCommitsBeforeVersioning = Number( exec( 'git rev-list --count HEAD' ) );
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return executeOnPackages( pathsCollection.matched, bumpVersionForSinglePackage )
|
|
301
|
-
.then( () => {
|
|
302
|
-
process.chdir( options.cwd );
|
|
303
|
-
|
|
304
|
-
const packageJson = getPackageJson( options.cwd );
|
|
305
|
-
const releaseDetails = packages.get( packageJson.name );
|
|
306
|
-
|
|
307
|
-
log.info( '\nCommitting and tagging changes...' );
|
|
308
|
-
|
|
309
|
-
exec( `git commit --message "Release: v${ releaseDetails.version }."` );
|
|
310
|
-
exec( `git tag v${ releaseDetails.version }` );
|
|
311
|
-
|
|
312
|
-
if ( dryRun ) {
|
|
313
|
-
const numberOfCommitsAfterVersioning = Number( exec( 'git rev-list --count HEAD' ) );
|
|
314
|
-
const commitsToRevert = numberOfCommitsAfterVersioning - numberOfCommitsBeforeVersioning;
|
|
315
|
-
|
|
316
|
-
logDryRun( `Reverting changes made by "npm version". Removing a tag and ${ commitsToRevert } commit(s).` );
|
|
317
|
-
exec( `git reset --hard HEAD~${ commitsToRevert }` );
|
|
318
|
-
exec( `git tag -d v${ releaseDetails.version }` );
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return packages;
|
|
322
|
-
} );
|
|
323
|
-
|
|
324
|
-
function bumpVersionForSinglePackage( repositoryPath ) {
|
|
325
|
-
process.chdir( repositoryPath );
|
|
326
|
-
|
|
327
|
-
const packageJson = getPackageJson( repositoryPath );
|
|
328
|
-
const releaseDetails = packages.get( packageJson.name );
|
|
329
|
-
|
|
330
|
-
log.info( `\nBumping version for "${ chalk.underline( packageJson.name ) }"...` );
|
|
331
|
-
|
|
332
|
-
exec( `npm version ${ releaseDetails.version } --no-git-tag-version --no-workspaces-update` );
|
|
333
|
-
exec( 'git add .' );
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function exec( command ) {
|
|
338
|
-
if ( dryRun ) {
|
|
339
|
-
log.info( `⚠️ ${ chalk.grey( 'Execute:' ) } "${ chalk.cyan( command ) }" in "${ chalk.grey.italic( process.cwd() ) }".` );
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return tools.shExec( command, { verbosity: 'error' } );
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function logProcess( message ) {
|
|
346
|
-
log.info( '\n📍 ' + chalk.cyan( message ) );
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function logDryRun( message ) {
|
|
350
|
-
if ( dryRun ) {
|
|
351
|
-
log.info( 'ℹ️ ' + chalk.yellow( message ) );
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
@@ -1,257 +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
|
-
/* eslint-env node */
|
|
7
|
-
|
|
8
|
-
'use strict';
|
|
9
|
-
|
|
10
|
-
const path = require( 'path' );
|
|
11
|
-
const fs = require( 'fs-extra' );
|
|
12
|
-
const chalk = require( 'chalk' );
|
|
13
|
-
const glob = require( 'glob' );
|
|
14
|
-
const { tools } = require( '@ckeditor/ckeditor5-dev-utils' );
|
|
15
|
-
const { getLastFromChangelog } = require( '../utils/versions' );
|
|
16
|
-
const executeOnPackages = require( '../utils/executeonpackages' );
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Fields that will not be removed from `package.json` while preparing a package.
|
|
20
|
-
*/
|
|
21
|
-
const PACKAGE_JSON_FIELDS = [
|
|
22
|
-
'author',
|
|
23
|
-
'dependencies',
|
|
24
|
-
'description',
|
|
25
|
-
'engine',
|
|
26
|
-
'homepage',
|
|
27
|
-
'license',
|
|
28
|
-
'keywords',
|
|
29
|
-
'name',
|
|
30
|
-
'version',
|
|
31
|
-
'files',
|
|
32
|
-
'main',
|
|
33
|
-
'types',
|
|
34
|
-
'scripts'
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Prepares packages to be released:
|
|
39
|
-
*
|
|
40
|
-
* * removes TypeScript sources (but keeps typings),
|
|
41
|
-
* * secures the code of packages,
|
|
42
|
-
* * replaces the main package entry point (use JS file instead of TS),
|
|
43
|
-
* * prepares builds for all packages if a command is specified as npm script.
|
|
44
|
-
*
|
|
45
|
-
* The dry-run mode is not supported as the script creates a directory that should not be tracked by Git.
|
|
46
|
-
*
|
|
47
|
-
* @param {Object} options
|
|
48
|
-
* @param {String} options.cwd Current working directory (packages) from which all paths will be resolved.
|
|
49
|
-
* @param {String} options.packages Where to look for sources of packages (dependencies).
|
|
50
|
-
* @param {String} options.releaseDirectory Where to copy the packages (dependencies).
|
|
51
|
-
* @param {String} options.changelogDirectory An absolute path to the directory where the `CHANGELOG.md` file is saved.
|
|
52
|
-
* @param {String} options.buildScript A name of npm script that builds the package. It is executed per package.
|
|
53
|
-
* @param {String} options.secureScript A name of npm script that secures the code in the entire repository.
|
|
54
|
-
* @param {Array.<String>} [options.npmScriptsToRemove=[]] An array of npm scripts that should be removed when processing a package.
|
|
55
|
-
* @returns {Promise}
|
|
56
|
-
*/
|
|
57
|
-
module.exports = async function preparePackages( options ) {
|
|
58
|
-
const cwd = process.cwd();
|
|
59
|
-
const packagesDirectory = path.join( options.cwd, options.packages );
|
|
60
|
-
const releaseDirectory = path.join( options.cwd, options.releaseDirectory );
|
|
61
|
-
const ckeditor5Version = getLastFromChangelog( options.changelogDirectory );
|
|
62
|
-
const npmScriptsToRemove = options.npmScriptsToRemove || [];
|
|
63
|
-
|
|
64
|
-
// Clean the release directory before doing anything.
|
|
65
|
-
logProcess( 'Removing the release directory...' );
|
|
66
|
-
await fs.remove( releaseDirectory );
|
|
67
|
-
|
|
68
|
-
// Copy packages to the temporary, release directory.
|
|
69
|
-
logProcess( 'Copying packages to release...' );
|
|
70
|
-
await fs.copy( packagesDirectory, releaseDirectory );
|
|
71
|
-
|
|
72
|
-
// Find all short package names in the release directory.
|
|
73
|
-
// Then, map the names to absolute paths and their `package.json`.
|
|
74
|
-
const directoryNames = ( await fs.readdir( releaseDirectory, { withFileTypes: true } ) )
|
|
75
|
-
.filter( dirent => dirent.isDirectory() )
|
|
76
|
-
.map( dirent => dirent.name )
|
|
77
|
-
.map( name => {
|
|
78
|
-
const packagePath = path.join( releaseDirectory, name );
|
|
79
|
-
const packageJson = require( path.join( packagePath, 'package.json' ) );
|
|
80
|
-
|
|
81
|
-
return [ packagePath, packageJson ];
|
|
82
|
-
} );
|
|
83
|
-
|
|
84
|
-
const packages = new Map( directoryNames );
|
|
85
|
-
|
|
86
|
-
// Filter out packages without changes. They won't be released.
|
|
87
|
-
logProcess( 'Verifying packages...' );
|
|
88
|
-
await filterOutPackagesWithoutChanges( packages, ckeditor5Version );
|
|
89
|
-
|
|
90
|
-
if ( !packages.size ) {
|
|
91
|
-
logProcess( 'Nothing to release. Aborting.' );
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
logProcess( 'Preparing packages...' );
|
|
96
|
-
await preparePackagesToBeReleased( packages, npmScriptsToRemove );
|
|
97
|
-
|
|
98
|
-
// Secure the entire release directory.
|
|
99
|
-
logProcess( 'Securing the code...' );
|
|
100
|
-
exec( options.secureScript );
|
|
101
|
-
|
|
102
|
-
logProcess( 'Preparing builds...' );
|
|
103
|
-
await prepareBuilds( packages, options.buildScript );
|
|
104
|
-
|
|
105
|
-
process.chdir( cwd );
|
|
106
|
-
|
|
107
|
-
logProcess( 'Done.' );
|
|
108
|
-
logInfo( chalk.grey( `Review the "${ options.releaseDirectory }/" directory before publishing the packages on npm.\n` ) );
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Check if packages should be released. It compares the packages' version against the latest version in CKEditor 5 changelog.
|
|
113
|
-
*
|
|
114
|
-
* If they are different, it means that a package should not be released and it is removed from the release directory.
|
|
115
|
-
*
|
|
116
|
-
* @param {Map.<String, PackageJson>} packages
|
|
117
|
-
* @param {String} ckeditor5Version
|
|
118
|
-
* @returns {Promise}
|
|
119
|
-
*/
|
|
120
|
-
function filterOutPackagesWithoutChanges( packages, ckeditor5Version ) {
|
|
121
|
-
return executeOnPackages( packages.keys(), async packagePath => {
|
|
122
|
-
const { name: packageName, version: packageVersion } = packages.get( packagePath );
|
|
123
|
-
|
|
124
|
-
logInfo( `* Checking "${ chalk.underline( packageName ) }"...`, { indent: 1, startWithNewLine: true } );
|
|
125
|
-
|
|
126
|
-
if ( packageVersion !== ckeditor5Version ) {
|
|
127
|
-
logInfo( chalk.grey( 'Nothing to release. Skipping.' ), { indent: 1 } );
|
|
128
|
-
|
|
129
|
-
await fs.remove( packagePath );
|
|
130
|
-
packages.delete( packagePath );
|
|
131
|
-
}
|
|
132
|
-
} );
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Prepare packages to be released. It means, for each package we do the following actions:
|
|
137
|
-
*
|
|
138
|
-
* * Remove TypeScript sources, but keep typing files (`.d.ts`).
|
|
139
|
-
* * Redefine the main script of a package. Replace the TypeScript extension with JavaScript.
|
|
140
|
-
* * Remove all tests of the package as they should not be released.
|
|
141
|
-
* * Remove the `build/` directory. The build script will re-create it from the JavaScript code.
|
|
142
|
-
*
|
|
143
|
-
* @param {Map.<String, PackageJson>} packages
|
|
144
|
-
* @param {Array.<String>} npmScriptsToRemove An array of npm scripts that should be removed when processing a package.
|
|
145
|
-
* @returns {Promise}
|
|
146
|
-
*/
|
|
147
|
-
function preparePackagesToBeReleased( packages, npmScriptsToRemove ) {
|
|
148
|
-
return executeOnPackages( packages.keys(), async packagePath => {
|
|
149
|
-
const { name: packageName } = packages.get( packagePath );
|
|
150
|
-
|
|
151
|
-
logInfo( `* Processing "${ chalk.underline( packageName ) }"...`, { indent: 1, startWithNewLine: true } );
|
|
152
|
-
logInfo( chalk.grey( 'Cleaning-up the package directory...' ), { indent: 2 } );
|
|
153
|
-
|
|
154
|
-
// The build will be refreshed. To avoid weird caches or building from TypeScript, let's clean the directory.
|
|
155
|
-
await fs.remove( path.join( packagePath, 'build' ) );
|
|
156
|
-
|
|
157
|
-
// Tests will not be published anyway. To increase readability, let's clean it too.
|
|
158
|
-
await fs.remove( path.join( packagePath, 'tests' ) );
|
|
159
|
-
|
|
160
|
-
// Update the entry point in the `package.json` file to point to a JavaScript file.
|
|
161
|
-
logInfo( chalk.grey( 'Replacing the package entry point (TS => JS)...' ), { indent: 2 } );
|
|
162
|
-
|
|
163
|
-
tools.updateJSONFile( path.join( packagePath, 'package.json' ), packageJson => {
|
|
164
|
-
const { main } = packageJson;
|
|
165
|
-
|
|
166
|
-
// Remove properties from package.json that are not related to the production package.
|
|
167
|
-
for ( const property of Object.keys( packageJson ) ) {
|
|
168
|
-
if ( !PACKAGE_JSON_FIELDS.includes( property ) ) {
|
|
169
|
-
delete packageJson[ property ];
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if ( 'scripts' in packageJson ) {
|
|
174
|
-
for ( const npmScript of npmScriptsToRemove ) {
|
|
175
|
-
delete packageJson.scripts[ npmScript ];
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if ( !main ) {
|
|
180
|
-
return packageJson;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
packageJson.main = main.replace( /.ts$/, '.js' );
|
|
184
|
-
packageJson.types = main.replace( /.ts$/, '.d.ts' );
|
|
185
|
-
|
|
186
|
-
return packageJson;
|
|
187
|
-
} );
|
|
188
|
-
|
|
189
|
-
// Find all TypeScript sources...
|
|
190
|
-
const typescriptFiles = await new Promise( ( resolve, reject ) => {
|
|
191
|
-
glob( '**/*.ts', { cwd: packagePath }, ( err, files ) => {
|
|
192
|
-
return err ? reject( err ) : resolve( files );
|
|
193
|
-
} );
|
|
194
|
-
} );
|
|
195
|
-
|
|
196
|
-
logInfo( chalk.grey( 'Removing TypeScript sources...' ), { indent: 2 } );
|
|
197
|
-
|
|
198
|
-
// ...and remove all non-typing files.
|
|
199
|
-
for ( const tsFile of typescriptFiles ) {
|
|
200
|
-
if ( !tsFile.endsWith( '.d.ts' ) ) {
|
|
201
|
-
await fs.remove( path.join( packagePath, tsFile ) );
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
} );
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Executed a build task for all packages.
|
|
209
|
-
*
|
|
210
|
-
* @param {Map.<String, PackageJson>} packages
|
|
211
|
-
* @param {String} buildScript
|
|
212
|
-
* @returns {Promise}
|
|
213
|
-
*/
|
|
214
|
-
function prepareBuilds( packages, buildScript ) {
|
|
215
|
-
return executeOnPackages( packages.keys(), async packagePath => {
|
|
216
|
-
const { name: packageName, scripts = {} } = packages.get( packagePath );
|
|
217
|
-
|
|
218
|
-
if ( buildScript in scripts ) {
|
|
219
|
-
logInfo( `* Processing "${ chalk.underline( packageName ) }"...`, { indent: 1, startWithNewLine: true } );
|
|
220
|
-
|
|
221
|
-
process.chdir( packagePath );
|
|
222
|
-
|
|
223
|
-
exec( `yarn run ${ buildScript }` );
|
|
224
|
-
}
|
|
225
|
-
} );
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* @param {String} message
|
|
230
|
-
*/
|
|
231
|
-
function logProcess( message ) {
|
|
232
|
-
console.log( '\n📍 ' + chalk.cyan( message ) );
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* @param {String} message
|
|
237
|
-
* @param {Object} options
|
|
238
|
-
* @param {Number} [options.indent=0]
|
|
239
|
-
* @param {Boolean} [options.startWithNewLine=false]
|
|
240
|
-
*/
|
|
241
|
-
function logInfo( message, { indent = 0, startWithNewLine = false } = {} ) {
|
|
242
|
-
console.log( ( startWithNewLine ? '\n' : '' ) + ' '.repeat( indent * 3 ) + message );
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* @param {String} command
|
|
247
|
-
* @returns {String}
|
|
248
|
-
*/
|
|
249
|
-
function exec( command ) {
|
|
250
|
-
return tools.shExec( command );
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* @typedef {Object} PackageJson
|
|
255
|
-
* @property {String} version
|
|
256
|
-
* @property {String} name
|
|
257
|
-
*/
|