Skip to content

Commit

Permalink
Project management: Add step that updates CHANGELOG files before npm …
Browse files Browse the repository at this point in the history
…releases (#19764)
  • Loading branch information
gziolo authored Jan 21, 2020
1 parent c22b77c commit b39e9d9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 18 deletions.
116 changes: 111 additions & 5 deletions bin/commander.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const inquirer = require( 'inquirer' );
const semver = require( 'semver' );
const chalk = require( 'chalk' );
const fs = require( 'fs' );
const glob = require( 'fast-glob' );
const readline = require( 'readline' );
const rimraf = require( 'rimraf' );
const SimpleGit = require( 'simple-git/promise' );
const childProcess = require( 'child_process' );
Expand Down Expand Up @@ -428,7 +430,7 @@ async function runBumpPluginVersionAndCommitStep( version, changelog, abortMessa
] );
const commitData = await simpleGit.commit( 'Bump plugin version to ' + version );
commitHash = commitData.commit;
console.log( '>> The plugin version bump has been commited successfully.' );
console.log( '>> The plugin version bump has been committed successfully.' );
} );

return commitHash;
Expand Down Expand Up @@ -730,12 +732,114 @@ async function runWordPressReleaseBranchSyncStep( abortMessage ) {
};
}

/**
* Update CHANGELOG files with the new version number for those packages that
* contain new entries.
*
* @param {string} minimumVersionBump Minimum version bump for the packages.
* @param {string} abortMessage Abort Message.
*/
async function updatePackageChangelogs( minimumVersionBump, abortMessage ) {
const changelogFiles = await glob( path.resolve( gitWorkingDirectoryPath, 'packages/*/CHANGELOG.md' ) );
const processedPackages = await Promise.all( changelogFiles.map( async ( changelogFile ) => {
const fileStream = fs.createReadStream( changelogFile );

const lines = readline.createInterface( {
input: fileStream,
} );

let changesDetected = false;
let versionBump = null;
for await ( const line of lines ) {
// Detect unpublished changes first.
if ( line.startsWith( '## Master' ) ) {
changesDetected = true;
continue;
}

// Skip all lines until unpublished changes found.
if ( ! changesDetected ) {
continue;
}

// A previous published version detected. Stop processing.
if ( line.startsWith( '## ' ) ) {
break;
}

// A major version bump required. Stop processing.
if ( line.startsWith( '### Breaking Change' ) ) {
versionBump = 'major';
break;
}

// A minor version bump required. Proceed to the next line.
if ( line.startsWith( '### New Feature' ) || line.startsWith( '### Deprecation' ) ) {
versionBump = 'minor';
continue;
}

// A version bump required. Found new changelog section.
if ( versionBump !== 'minor' && line.startsWith( '### ' ) ) {
versionBump = minimumVersionBump;
}
}
const packageName = `@wordpress/${ changelogFile.split( '/' ).reverse()[ 1 ] }`;
const { version } = readJSONFile( changelogFile.replace( 'CHANGELOG.md', 'package.json' ) );
const nextVersion = ( versionBump !== null ) ?
semver.inc( version, versionBump ) :
null;

return {
changelogFile,
packageName,
version,
nextVersion,
};
} ) );

const changelogsToUpdate = processedPackages.
filter( ( { nextVersion } ) => nextVersion );

if ( changelogsToUpdate.length === 0 ) {
console.log( '>> No changes in CHANGELOG files detected.' );
return;
}

console.log( '>> Recommended version bumps based on the changes detected in CHANGELOG files:' );

const publishDate = new Date().toISOString().split( 'T' )[ 0 ];
await Promise.all(
changelogsToUpdate
.map( async ( { changelogFile, packageName, nextVersion, version } ) => {
const content = await fs.promises.readFile( changelogFile, 'utf8' );
await fs.promises.writeFile( changelogFile, content.replace(
'## Master',
`## Master\n\n## ${ nextVersion } (${ publishDate })`
) );
console.log( ` - ${ packageName }: ${ version } -> ${ nextVersion }` );
} )
);

await askForConfirmationToContinue(
`All corresponding files were updated. Commit the changes?`,
true,
abortMessage
);
const simpleGit = SimpleGit( gitWorkingDirectoryPath );
await simpleGit.add( './*' );
await simpleGit.commit( 'Update changelog files' );
console.log( '>> Changelog files changes have been committed successfully.' );
}

/**
* Prepublish to npm steps for WordPress packages.
*
* @param {string} minimumVersionBump Minimum version bump for the packages.
*
* @return {Object} Github release object.
*/
async function prepublishPackages() {
async function prepublishPackages( minimumVersionBump ) {
// This is a variable that contains the abort message shown when the script is aborted.
let abortMessage = 'Aborting!';
await askForConfirmationToContinue( 'Ready to go? ' );
Expand All @@ -746,6 +850,8 @@ async function prepublishPackages() {
// Checking out the WordPress release branch and doing sync with the last plugin release.
const { releaseBranch } = await runWordPressReleaseBranchSyncStep( abortMessage );

await updatePackageChangelogs( minimumVersionBump, abortMessage );

// Push the local changes
abortMessage = `Aborting! Make sure to push changes applied to WordPress release branch "${ releaseBranch }" manually.`;
await runPushGitChangesStep( releaseBranch, abortMessage );
Expand All @@ -757,15 +863,15 @@ async function prepublishPackages() {
program
.command( 'prepublish-packages-stable' )
.alias( 'npm-stable' )
.description( 'Prepublish to npm steps for a stable version of WordPress packages' )
.description( 'Prepublish to npm steps for the next stable version of WordPress packages' )
.action( async () => {
console.log(
chalk.bold( '💃 Time to publish WordPress packages to npm 🕺\n\n' ),
'Welcome! This tool is going to help you with prepublish to npm steps for a new stable version of WordPress packages.\n',
'Welcome! This tool is going to help you with prepublish to npm steps for the next stable version of WordPress packages.\n',
'To perform a release you\'ll have to be a member of the WordPress Team on npm.\n'
);

await prepublishPackages();
await prepublishPackages( 'minor' );

console.log(
'\n>> 🎉 WordPress packages are ready to publish.\n',
Expand Down
27 changes: 14 additions & 13 deletions docs/contributors/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ The Gutenberg repository mirrors the [WordPress SVN repository](https://make.wor

### Synchronizing WordPress Trunk

For each Gutenberg plugin release, WordPress trunk should be synchronized with this release. This involves the following steps:
For each Gutenberg plugin release, WordPress trunk should be synchronized with this release. This involves the following steps that are automated with `./bin/commander npm-stable` command:

**Note:** The WordPress `trunk` branch can be closed or in "feature-freeze" mode. Usually, this happens between the first `beta` and the first `RC` of the WordPress release cycle. During this period, the Gutenberg plugin releases should not be synchronized with WordPress Core.

Expand All @@ -219,12 +219,13 @@ For each Gutenberg plugin release, WordPress trunk should be synchronized with t
3. Remove all files from the current branch: `git rm -r .`.
4. Check out all the files from the release branch: `git checkout release/x.x -- .`.
5. Commit all changes to the `wp/trunk` branch with `git commit -m "Merge changes published in the Gutenberg plugin vX.X release"` and push to the repository.
6. Update the `CHANGELOG.md` files of the packages with the new publish version calculated and commit to the `wp/trunk` branch.
Aassuming the package versions are written using this format `major.minor.patch`, make sure to bump at least the `minor` version number. For example, if the CHANGELOG of the package to be released indicates that the next unreleased version is `5.6.1`, choose `5.7.0` as a version in case of `minor` version.

Now, the branch is ready to be used to publish the npm packages.

1. Run the [package release process] but when asked for the version numbers to choose for each package, (assuming the package versions are written using this format `major.minor.patch`) make sure to bump at least the `minor` version number. For example, if the CHANGELOG of the package to be released indicates that the next unreleased version is `5.6.1`, choose `5.7.0` as a version.
2. Update the `CHANGELOG.md` files of the published packages with the new released versions and commit to the `wp/trunk` branch.
3. Cherry-pick the "Publish" (created by Lerna) and the CHANGELOG update commits into the `master` branch of Gutenberg.
1. Run the [package release process] but when asked for the version numbers to choose for each package pick values based on the updated CHANGELOG files.
2. Cherry-pick the "Publish" (created by Lerna) and the CHANGELOG update commits into the `master` branch of Gutenberg.

Now, the npm packages should be ready and a patch can be created and committed into WordPress `trunk`.

Expand Down Expand Up @@ -254,7 +255,7 @@ Now, the branch is ready to be used to publish the npm packages.
Now, the npm packages should be ready and a patch can be created and committed into the corresponding WordPress SVN branch.


### Standalone Package Releases
### Standalone Package Releases

The following workflow is needed when packages require bug fixes or security releases to be published to _npm_ outside of a WordPress release cycle.

Expand All @@ -276,7 +277,7 @@ Before porting commits check that the `wp/trunk` branch does not have any outsta

Now _cherry-pick_ the commits from `master` to `wp/trunk`, use `-m 1 commithash` if the commit was a pull request merge commit:
1. `git cherry-pick -m 1 cb150a2`
2. `git push`
2. `git push`

Whilst waiting for the Travis CI build for `wp/trunk` [branch to pass](https://travis-ci.com/WordPress/gutenberg/branches) identify and begin updating the `CHANGELOG.md` files:
1. `git checkout wp/trunk`
Expand Down Expand Up @@ -317,23 +318,23 @@ Now that the changes have been committed to the `wp/trunk` branch and the Travis
> @wordpress/scripts
> lerna success found 3 packages ready to publish
> ```
2. Run the [package release process](https://github.com/WordPress/gutenberg/blob/master/packages/README.md#releasing-packages) but when asked for the version numbers to choose for each package use the versions you made note of above when updating each packages `CHANGELOG.md` file.
2. Run the [package release process] but when asked for the version numbers to choose for each package use the versions you made note of above when updating each packages `CHANGELOG.md` file.
> Truncated example of publishing process output
> ```
> npm run publish:prod
>
>
> Build Progress: [==============================] 100%
> lerna notice cli v3.18.2
> lerna info versioning independent
> ? Select a new version for @wordpress/e2e-tests (currently 1.9.0) Patch (1.9.1)
> ? Select a new version for @wordpress/jest-preset-default (currently 5.3.0) Patch (5.3.1)
> ? Select a new version for @wordpress/scripts (currently 6.1.0) Patch (6.1.1)
>
>
> Changes:
> - @wordpress/e2e-tests: 1.9.0 => 1.9.1
> - @wordpress/jest-preset-default: 5.3.0 => 5.3.1
> - @wordpress/scripts: 6.1.0 => 6.1.1
>
>
> ? Are you sure you want to publish these packages? Yes
> lerna info execute Skipping releases
> lerna info git Pushing tags...
Expand All @@ -359,21 +360,21 @@ Now that the packages have been published the _"chore(release): publish"_ and _"
5. Get the commit hash from the the lerna publish commit either from the terminal or [wp/trunk commits](https://github.com/WordPress/gutenberg/commits/wp/trunk)
6. Cherry-pick the `fe6ae0d` "chore(release): publish"_ commit made to `wp/trunk`
7. `git cherry-pick fe6ae0d`
8. `git push`
8. `git push`
Confirm the packages dependancies do not contain `file://` links in the `dependencies` or `devdependencies` section of the packages released, e.g:
> https://unpkg.com/browse/@wordpress/jest-preset-default@5.3.1/package.json
> https://unpkg.com/browse/@wordpress/scripts@6.1.1/package.json
> https://unpkg.com/browse/@wordpress/jest-preset-default@5.3.1/package.json
Time to announce the published changes in the #core-js and #core-editor Slack channels
Time to announce the published changes in the #core-js and #core-editor Slack channels
> ```
> 📣 Successfully published:
> • @wordpress/e2e-tests@1.9.1
> • @wordpress/jest-preset-default@5.3.1
> • @wordpress/scripts@6.1.1
> Lerna success published 3 packages
```
> ```
---------
Expand Down

0 comments on commit b39e9d9

Please sign in to comment.