Skip to content

Commit

Permalink
Merge pull request #728 from ckeditor/ck/10583
Browse files Browse the repository at this point in the history
Fix: The `getPackagesToRelease()` function handles pre-release versions properly. Closes ckeditor/ckeditor5#10583.
  • Loading branch information
pomek authored Sep 23, 2021
2 parents 173c45a + 763d169 commit ec16756
Show file tree
Hide file tree
Showing 2 changed files with 293 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,59 @@ module.exports = function getPackagesToRelease( pathsToPackages, options ) {
// [packageName](https://www.npmjs.com/package/packageName): v0.0.1
//
// where:
// `v0.0.1` is the current version (not published yet),
// `v0.0.1` is the current version (not published yet).
//
// The function handles pre-release, so, e.g. `v1.0.0.alpha.0` is also a proper input.
//
// Keep in mind that the dash (`-`) is a separator of the pre-release. Other characters are not allowed
// and npm will not publish a package if its version does not contain the symbol.
//
// @param {String} changelog Changes.
// @param {String} packageName Package to look.
// @returns {String|null} `null` if the version was not found.
function findVersionInChangelog( changelog, packageName ) {
const existingPackageRegExp = new RegExp( `\\[${ packageName.replace( '/', '\\/' ) }\\].*v[\\d.]+\\ => v([\\d.]+)` );
// Pick: `x.y.z` or `x.y.z-prerelease.n`, assumptions: `x, y, z, n = { 0, 1, 2, ... }`.
const semVer = '\\d+\\.\\d+\\.\\d+(.[a-z\\d.]+)?';

const existingPackageRegExp = new RegExp( `\\[${ packageName.replace( '/', '\\/' ) }\\].*v(${ semVer })+\\ (=>) v(${ semVer })` );
// Groups:
// 1. Previous version.
// 2. Previous version - pre-release part.
// 3. "=>" character that suggests that the package exists on npm.
// 4. New version.
// 5. New version - pre-release part.

let match = changelog.match( existingPackageRegExp );

// The package exists on npm.
if ( match ) {
return match[ 1 ];
// The version does not match to `x.y.z-prerelease.n`, npm will not allow publish it.
if ( match[ 5 ] && !match[ 5 ].startsWith( '-' ) ) {
return null;
}

return match[ 4 ];
}

const newPackageRegExp = new RegExp( `\\[${ packageName.replace( '/', '\\/' ) }\\].*v([\\d.]+)` );
// At this stage, we know that it will be the first release of `packageName`.
// If the specified version is correct, let's use it.
const newPackageRegExp = new RegExp( `\\[${ packageName.replace( '/', '\\/' ) }\\].*v(${ semVer })` );
// Groups:
// 1. New version.
// 2. New version - pre-release part.

match = changelog.match( newPackageRegExp );

return match ? match[ 1 ] : null;
if ( !match ) {
return null;
}

// The version does not match to `x.y.z-prerelease.n`, npm will not allow publish it.
if ( match[ 2 ] && !match[ 2 ].startsWith( '-' ) ) {
return null;
}

return match[ 1 ];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,257 @@ describe( 'dev-env/release-tools/utils', () => {
expect( corePackage.version ).to.equal( '1.0.0' );
} );
} );

// See: https://github.com/ckeditor/ckeditor5/issues/10583.
describe( 'pre-release versions', () => {
it( 'returns proper versions for existing packages (alpha release)', () => {
const packagesToCheck = new Set( [
'/cwd',
'/packages/ckeditor5-core'
] );

// ckeditor5
stubs.getPackageJson.onFirstCall().returns( {
name: 'ckeditor5',
version: '1.0.0'
} );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onSecondCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '1.0.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[ckeditor5](npm link): v1.0.0 => v2.0.0-alpha.0',
'[@ckeditor/ckeditor5-core](npm link): v1.0.0 => v2.0.0-alpha.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '2.0.0-alpha.0' } )
.then( packages => {
expect( packages.size ).to.equal( 2 );

expect( stubs.chdir.calledThrice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/cwd' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.thirdCall.args[ 0 ] ).to.equal( '/cwd' );

const corePackage = packages.get( '@ckeditor/ckeditor5-core' );
expect( corePackage.version ).to.equal( '2.0.0-alpha.0' );

const ckeditor5Package = packages.get( 'ckeditor5' );
expect( ckeditor5Package.version ).to.equal( '2.0.0-alpha.0' );
} );
} );

it( 'returns proper versions for existing packages (release candidate)', () => {
const packagesToCheck = new Set( [
'/cwd',
'/packages/ckeditor5-core'
] );

// ckeditor5
stubs.getPackageJson.onFirstCall().returns( {
name: 'ckeditor5',
version: '2.0.0-alpha.0'
} );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onSecondCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '2.0.0-alpha.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[ckeditor5](npm link): v2.0.0-alpha.0 => v2.0.0-rc.0',
'[@ckeditor/ckeditor5-core](npm link): v2.0.0-alpha.0 => v2.0.0-rc.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '2.0.0-rc.0' } )
.then( packages => {
expect( packages.size ).to.equal( 2 );

expect( stubs.chdir.calledThrice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/cwd' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.thirdCall.args[ 0 ] ).to.equal( '/cwd' );

const corePackage = packages.get( '@ckeditor/ckeditor5-core' );
expect( corePackage.version ).to.equal( '2.0.0-rc.0' );

const ckeditor5Package = packages.get( 'ckeditor5' );
expect( ckeditor5Package.version ).to.equal( '2.0.0-rc.0' );
} );
} );

it( 'returns proper versions for existing packages (from alpha to release candidate)', () => {
const packagesToCheck = new Set( [
'/cwd',
'/packages/ckeditor5-core'
] );

// ckeditor5
stubs.getPackageJson.onFirstCall().returns( {
name: 'ckeditor5',
version: '1.0.0'
} );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onSecondCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '1.0.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[ckeditor5](npm link): v1.0.0 => v2.0.0-rc.0',
'[@ckeditor/ckeditor5-core](npm link): v1.0.0 => v2.0.0-rc.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '2.0.0-rc.0' } )
.then( packages => {
expect( packages.size ).to.equal( 2 );

expect( stubs.chdir.calledThrice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/cwd' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.thirdCall.args[ 0 ] ).to.equal( '/cwd' );

const corePackage = packages.get( '@ckeditor/ckeditor5-core' );
expect( corePackage.version ).to.equal( '2.0.0-rc.0' );

const ckeditor5Package = packages.get( 'ckeditor5' );
expect( ckeditor5Package.version ).to.equal( '2.0.0-rc.0' );
} );
} );

it( 'returns proper versions for new packages (alpha release)', () => {
const packagesToCheck = new Set( [
'/cwd',
'/packages/ckeditor5-core'
] );

// ckeditor5
stubs.getPackageJson.onFirstCall().returns( {
name: 'ckeditor5',
version: '1.0.0'
} );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onSecondCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '1.0.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[ckeditor5](npm link): v1.0.0-alpha.0',
'[@ckeditor/ckeditor5-core](npm link): v1.0.0-alpha.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '1.0.0-alpha.0' } )
.then( packages => {
expect( packages.size ).to.equal( 2 );

expect( stubs.chdir.calledThrice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/cwd' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.thirdCall.args[ 0 ] ).to.equal( '/cwd' );

const corePackage = packages.get( '@ckeditor/ckeditor5-core' );
expect( corePackage.version ).to.equal( '1.0.0-alpha.0' );

const ckeditor5Package = packages.get( 'ckeditor5' );
expect( ckeditor5Package.version ).to.equal( '1.0.0-alpha.0' );
} );
} );

it( 'does not return a package if a version misses the "dash" symbol (an existing package)', () => {
const packagesToCheck = new Set( [
'/packages/ckeditor5-core'
] );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onFirstCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '1.0.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[@ckeditor/ckeditor5-core](npm link): v1.0.0 => v2.0.0.alpha.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '2.0.0-alpha.0' } )
.then( packages => {
expect( packages.size ).to.equal( 0 );

expect( stubs.chdir.calledTwice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/cwd' );
} );
} );

it( 'does not return a package if a version misses the "dash" symbol (an existing package, from alpha to rc)', () => {
const packagesToCheck = new Set( [
'/packages/ckeditor5-core'
] );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onFirstCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '2.0.0-alpha.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[@ckeditor/ckeditor5-core](npm link): v2.0.0-alpha.0 => v2.0.0.rc.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '2.0.0-rc.0' } )
.then( packages => {
expect( packages.size ).to.equal( 0 );

expect( stubs.chdir.calledTwice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/cwd' );
} );
} );

it( 'does not return a package if a version misses the "dash" symbol (a new package)', () => {
const packagesToCheck = new Set( [
'/packages/ckeditor5-core'
] );

// @ckeditor/ckeditor5-core
stubs.getPackageJson.onFirstCall().returns( {
name: '@ckeditor/ckeditor5-core',
version: '1.0.0'
} );

sandbox.stub( process, 'cwd' ).returns( '/cwd' );

const changes = [
'[@ckeditor/ckeditor5-core](npm link): v1.0.0.alpha.0'
].join( '\n' );

return getPackagesToRelease( packagesToCheck, { changes, version: '1.0.0-alpha.0' } )
.then( packages => {
expect( packages.size ).to.equal( 0 );

expect( stubs.chdir.calledTwice ).to.equal( true );
expect( stubs.chdir.firstCall.args[ 0 ] ).to.equal( '/packages/ckeditor5-core' );
expect( stubs.chdir.secondCall.args[ 0 ] ).to.equal( '/cwd' );
} );
} );
} );
} );
} );

0 comments on commit ec16756

Please sign in to comment.