Preface
Releases are a brittle and sensitive process. There are often a lot of steps involved:
- Update CHANGELOG
- Commit CHANGELOG (e.g.
git commit) - Update semver in repository files (e.g.
package.json,setup.py) - Commit semver changes (e.g.
git commit) - Tag release commit (e.g.
git tag 1.0.0) - Push committed versions (e.g.
git push) - Push committed tags (e.g.
git push --tags) - Publish to repository (e.g.
npm publish,python setup.py sdist --formats=gztar,zip upload)
If we forget any step, then we might need to start all over. Or if we notice a typo in our documentation, we will need to perform another release.
As soon as we recognized this bottleneck, we started automating it as much as possible:
- Initially via an integration with
git-extras' releasecommand: - Then, with
foundryas a plugin based release manager:
Release v4
The past revisions of foundry have had a few problems which bugged me:
- Releases were not transparent (e.g. we didn't know what command would fail without looking at source code)
- If a release fails, then there is no easy way to resume (e.g. forgot to log in to
npm, repository is randomly sending 500's) - Language exclusive (e.g. PyPI release command is written in JavaScript, not Python so we can't leverage its AST)
- If a local
foundryisn't found, then the global one will be used automatically - No support for custom commands (e.g. we can't add a
./build.shwhen updating files without writing a plugin)
To resolve this, we took the following approach:
- Moved to CLI based commands rather than plugins
- Allows specification to be cross-language
- Opens avenue for writing custom commands in configuration
- Allows for transparent execution of each step since we own the CLI invocation
- Moved to deterministic release steps
- Allows for resuming failed releases
- Moved to current working directory
package.json/.foundryrcfor release configuration- Removes possibility of running global
foundry - Allows for customization of things like
registerVersion(semver to run "register" steps at)
- Removes possibility of running global
Results
All of the proposed changes are now live in foundry.
https://github.com/twolfson/foundry/tree/4.3.2
We revamped foundry-release-spec to be a CLI specification:
- Before: https://github.com/twolfson/foundry-release-spec/tree/1.1.0
- After: https://github.com/twolfson/foundry-release-spec/tree/2.0.0
We wrote foundry-release-base to migrate our plugins to command integrations:
https://github.com/twolfson/foundry-release-base/tree/1.0.2
We updated foundry release to generate a foundry-resume.json upon failure. This allows for usage of foundry resume which picks up the release from where it last failed.
We added support for customCommand as part of our releaseCommands. This allows for custom one-off commands (e.g. updateFiles: 'npm run build').
Lastly, we added more transparent output so we always know exactly where we are in our release:

The full list of our thoughts and changes can be found here: