Skip to content

Essential: Installation

Will Sargent edited this page May 2, 2020 · 24 revisions

Index

  1. Motivation: First time here? Understand what sbt-release-early does and how.
  2. Requirements: Wanna install? Make sure your system is set up.
  3. Installation: You know everything and just want to install it? Come here.
  4. Use: Check instructions on how to use the plugin.
  5. Configuration: click on the link, you're on the wrong page.

Motivation

In a nutshell

Every time you push a commit to a branch, sbt-release-early will release an artifact with a version derived from the git metadata (version and distance from last git tag). For example, 0.3.0+10-4f489199, where 10 is the distance and the suffix is the commit hash.

Every time you push a tag to a repository, sbt-release-early will release an artifact with that tag version. This feature is usually used to cut final releases, for example, v0.1.0.

Why this way

sbt-release-early takes a distinct approach to releases.

While some projects decide to declare versions in sbt files, sbt-release-early derives the versions of your project from your git tags. This has several benefits:

  1. Reproducibility.
  2. Tag uniqueness. Git prevents you from trying to release a version twice by mistake.
  3. No need to push commits to bump up the versions of your projects.
  4. The tag history shows all the released versions over the time of a project.
  5. You can avoid releasing artifacts that can be resolved from resolvers.

These properties reduce the complexity of handling releases significantly. The repository revision history becomes the ultimate truth and build-related tasks are easy to set up -- no need to resolve the latest version or scrape the library version from its sbt build.

Note that the tag uniqueness property only holds if you don't delete an already pushed tag. This is so bad practice that we assume people are sensible and don't do it.

Version schema

The version lingo is extracted from the Semantic Versioning document.

This documentation and this plugin assumes that:

  • Version numbers are final if they only consist of a MAJOR, MINOR and PATCH VERSION. For example, 1.0.1, 2.4.98 and 10.1.6 are final releases.
  • Any other version number that contains build metadata or qualifiers like RC, beta or alpha are considered SNAPSHOTs even if they lack the -SNAPSHOT suffix. For example, 0.3.0+10-4f489199, 8.9.1-1f43aa21 or 1.0.0-RC are snapshots.

Note that the snapshot does not have a precise and commonly accepted definition. sbt-release-earlys definition differs from the common understanding of snapshot versions in the Scala community.

sbt-release-early considers the most literal definition of snapshot: it's a release that mirrors the codebase at a given point of time and whose artifacts could not provide the same guarantees as final releases. These guarantees are established by library authors.

Why not regular -SNAPSHOTs?

Snapshots have important shortcomings:

  1. They are not reproducible: downstream users can get different snapshot releases depending on the time they resolve/update them.
  2. Their resolution times are slower: build tools have to check all artifacts in all resolvers to choose the appropriate version.

The use of snapshots is no longer justified with sbt-release-early and sbt plugins like sbt-dynver that derive automatic versions from git invariants. sbt-release-early keeps your builds faster and more reproducible.

The use of snapshots may be justified for local development, but should be prohibited at the moment it leaves the local workspace. sbt-release-early enables this use case.

Differences with sbt-release

I already use the popular sbt-release plugin to create my own release pipeline. Why should I use sbt-release-early instead? Why have you spent time in this release plugin?

In my view, sbt-release makes ad-hoc design decisions that:

  • Complicate its use and understanding;
  • Require longer time to master; and,
  • Hamper maintenance and addition of new features.

We've created sbt-release-early to become the de-facto releasing plugin in the sbt community. For that, we've focused on simplicity and extensibility. That's why we've redesigned the releasing sbt experience.

Advantages over sbt-release

  • sbt-release-early can be invoked only for concrete projects and aggregation works out of the box. sbt-release has clunky support for aggregation and uses commands, which are global and cannot be executed only for a project.
  • sbt-release-early is easier to learn and customize. It reuses the task graph and does not require an ad-hoc dsl to specify the release pipeline. This alone eases the learning curve considerably.
    • Do you want to run a task after publish? Use dependsOn.
    • Do you want to run a task before publish? Use triggeredBy.
    • Do you want to change one pipeline step? No need to copy-paste all the sbt-release default steps.
  • sbt-release-early is only about releasing. sbt-release tries to create a release pipeline that aggregates lots of complicated steps (running tests, reading git tags, et cetera). Some drawbacks that come to mind:
    • You cannot reuse your release pipeline without waiting for all these steps to finish.
    • Running tests is insecure in CI servers.
  • sbt-release-early encourages remote releases in CI servers, while sbt-release's design is biased towards local releases (requiring users' input on several release steps).
  • sbt-release-early abstracts over whichever publisher you want to release to. sbt-release forces you to change the underlying publish sbt plugins by hand every time.
  • sbt-release-early has an opinionated handling of versions (delegating in sbt-dynver), sbt-release relies heavily on -SNAPSHOTs and forces users to set the versions in an sbt file.
  • sbt-release-early can be called directly from other plugins. sbt-release cannot do it without using internal tricks to invoke commands. These tricks slow down sbt.
  • sbt-release-early is actively maintained by the Scala Center and excellent external contributors. sbt-release is rarely updated.
  • sbt-release-early will not publish a project if an artifact of that project for the given version can be resolved, because it assumes that it has already been released. sbt-release will try to release and override the previous artifacts.

Disadvantages over sbt-release

  • sbt-release-early cannot suggest a version. The version is always set from the VCS environment.

Requirements

To use sbt-release-early, you must:

  1. Use git and have it executable both locally and in the CI (required by sbt-dynver).
  2. Have a GPG key and publish it to a PGP server like pgp.mit.edu.

Don't you meet these requirements?

  1. Install git and make it executable (for all the platforms).
  2. Read the guide to create and publish your own gpg key.

Dependencies

This plugin depends on the following sbt plugins:

If you already depend on them, remove them from your plugins.sbt file. The addSbtPlugin line above will bring them in automatically.

Installation

Add the plugin to your build with:

// defined in project/plugins.sbt
addSbtPlugin("ch.epfl.scala" % "sbt-release-early" % "2.1.1")

To find out what's the last available stable release, check the tag releases in this repository.

Depend on a pull-request or unreleased change

These are the last published versions to Maven Central.

Note that on-merge releases have no binary or source compatibility guarantees. They include changes that have been merged from pull requests and had not yet been as scrutinized as possible.

Use

  1. Make sure you fulfill all the requirements.
  2. Make sure you understand what the plugin does and how.
  3. Make sure your sbt build is set up correctly (by reading the Configuration).
  4. Make sure your CI server is ready (by reading the How To's on the sidebar).
  5. Run sbt releaseEarly in your CI and have fun.