jonelantha: Blog


Performing a semantic-release dry-run locally (without too much hassle...)

26th March 2020

Are you using semantic-release in your npm package workflow? Here's a quick guide on how to setup local sanity checking of your release notes

The problem

I recently setup a GitHub Actions workflow to make use of semantic-release to assist with the chores of releasing an npm package. My workflow was based on the example in the Using semantic-release with GitHub Actions guide - all was good!

But wait... how can I sanity check my release notes (or changelog entry) before I publish? I'd prefer not to be tweaking commit messages once my branch has been pushed up and likewise I'd prefer not to have to edit the changelog afterwards either.

semantic-release does support a --dry-run flag and it should be possible to integrate this into a workflow, but wouldn't it be nice if we could just run this locally before pushing to GitHub?

There is support for running a dry run locally but there's a few caveats:

  • your local dev setup will need to be authed with npm. This might not be a problem for you but if you work in a team then you'll probably find not everyone will be logged into npm. Or maybe (like me) you prefer your local dev environment to not be logged in (to prevent accidents!)
  • you'll need to be working on a release branch. This means master, beta etc (depending on your semantic-release config). Chances are it's a feature branch you're working on - so you'll probably find semantic-release refuses to perform the dry-run.

The solution

After trying various approaches I came up with a solution with an adapative semantic-release config file:

./release.config.js

const { execSync } = require('child_process');

module.exports = isDryRun() ? getDryRunConfig() : getCIConfig();

function getDryRunConfig() {
  return {
    repositoryUrl: getLocalRepoUrl(),
    branches: getCurrentBranch(),
    plugins: [
      '@semantic-release/commit-analyzer',
      '@semantic-release/release-notes-generator',
    ],
  };
}

function getCIConfig() {
  // contains your normal semantic-release config
  // this will be used on your CI environment
  return {
    plugins: [
      '@semantic-release/commit-analyzer',
      '@semantic-release/release-notes-generator',
      '@semantic-release/changelog',
      '@semantic-release/npm',
      '@semantic-release/github',
    ],
  };
}

function isDryRun() {
  return process.argv.includes('--dry-run');
}

function getLocalRepoUrl() {
  const topLevelDir = execSync('git rev-parse --show-toplevel')
    .toString()
    .trim();

  return `file://${topLevelDir}/.git`;
}

function getCurrentBranch() {
  return execSync('git rev-parse --abbrev-ref HEAD')
    .toString()
    .trim();
}

With this in place, if you perform a local dry run (using npx semantic-release --dry-run) you should see a preview of your release notes including the next version number.

NOTE: the generated version number may not be accurate depending on how behind your feature branch is with master. If in doubt, pull down master and merge.

So how does it work? It detects if it's a dry run (by checking for the presence of the --dry-run flag) and if so uses a config tailored for dry runs. This config is much simplified to just focus on the minimum steps needed to generate the relase notes. Crucially it tells semantic-release that the current feature branch is valid as a release branch and it also provides the local git repo as the origin (otherwise sementic-release may complain that your branch doesn't yet exist on origin).

If you implement the above you should have a nice local way to sanity check your release notes before publishing.

Happy semantic releasing!


© 2003-2020 jonelantha