Todd Wolfson

Software Engineer

October 17, 2015


Releases are a brittle and sensitive process. There are often a lot of steps involved:

  1. Update CHANGELOG
  2. Commit CHANGELOG (e.g. git commit)
  3. Update semver in repository files (e.g. package.json,
  4. Commit semver changes (e.g. git commit)
  5. Tag release commit (e.g. git tag 1.0.0)
  6. Push committed versions (e.g. git push)
  7. Push committed tags (e.g. git push --tags)
  8. Publish to repository (e.g. npm publish, python 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:

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 foundry isn't found, then the global one will be used automatically
  • No support for custom commands (e.g. we can't add a ./ when 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/.foundryrc for release configuration
    • Removes possibility of running global foundry
    • Allows for customization of things like registerVersion (semver to run "register" steps at)


All of the proposed changes are now live in foundry.

We revamped foundry-release-spec to be a CLI specification:

We wrote foundry-release-base to migrate our plugins to command integrations:

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:

foundry release screenshot

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

Top articles

Lessons of a startup engineer

Lessons from being a 3x first engineer, former Uber engineer, and working at even more startups

Develop faster

Removing the tedium from creating, developing, and publishing repos.

Sexy bash prompt

A bash prompt with colors, git statuses, and git branches.