Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project management: Add step that updates CHANGELOG files before npm releases #19764

Merged
merged 1 commit into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -427,7 +429,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 @@ -729,12 +731,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 @@ -745,6 +849,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 @@ -756,15 +862,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/[email protected]/package.json
> https://unpkg.com/browse/@wordpress/[email protected]/package.json
> https://unpkg.com/browse/@wordpress/[email protected]/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/[email protected]
> • @wordpress/[email protected]
> • @wordpress/[email protected]
> Lerna success published 3 packages
```
> ```

---------

Expand Down