• Stars
    star
    278
  • Rank 145,805 (Top 3 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created about 6 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

sbt plugin to automate Sonatype releases from GitHub Actions

sbt-ci-release

CI

This is an sbt plugin to help automate releases to Sonatype and Maven Central from GitHub Actions.

  • git tag pushes are published as regular releases to Maven Central
  • merge into main commits are published as -SNAPSHOT with a unique version number for every commit

Beware that publishing from GitHub Actions requires you to expose Sonatype credentials as secret environment variables in GitHub Actions jobs. However, secret environment variables are not accessible during pull requests.

Let's get started!

Sonatype

First, follow the instructions in https://central.sonatype.org/pages/ossrh-guide.html to create a Sonatype account and make sure you have publishing rights for a domain name. This is a one-time setup per domain name.

If you don't have a domain name, you can use io.github.<@your_username>. Here is a template you can use to write the Sonatype issue:

Title:
Publish rights for io.github.sbt
Description:
Hi, I would like to publish under the groupId: io.github.sbt.
It's my GitHub account https://github.com/sbt/

Optional: create user tokens

If you prefer not to save your actual username and password in GitHub Actions settings below, generate your user tokens:

  • login to https://s01.oss.sonatype.org/ (or https://oss.sonatype.org/ if your Sonatype account was created before February 2021),
  • click your username in the top right, then profiles,
  • in the tab that was opened, click on the top left dropdown, and select "User Token",
  • click "Access User Token", and save the name and password parts of the token somewhere safe.

sbt

Next, install this plugin in project/plugins.sbt

Maven Central

// sbt 1 only, see FAQ for 0.13 support
addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "<version>")

By installing sbt-ci-release the following sbt plugins are also brought in:

  • sbt-dynver: sets the version number based on your git history
  • sbt-pgp: to cryptographically sign the artifacts before publishing
  • sbt-sonatype: to publish artifacts to Sonatype
  • sbt-git: to automatically populate scmInfo

Make sure build.sbt does not define any of the following settings

  • version: handled by sbt-dynver
  • publishTo: handled by sbt-ci-release
  • publishMavenStyle: handled by sbt-ci-release
  • credentials: handled by sbt-sonatype

Next, define publishing settings at the top of build.sbt

inThisBuild(List(
  organization := "com.github.sbt",
  homepage := Some(url("https://github.com/sbt/sbt-ci-release")),
  // Alternatively License.Apache2 see https://github.com/sbt/librarymanagement/blob/develop/core/src/main/scala/sbt/librarymanagement/License.scala
  licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")),
  developers := List(
    Developer(
      "olafurpg",
      "Ólafur Páll Geirsson",
      "[email protected]",
      url("https://geirsson.com")
    )
  )
))

If your sonatype account is new (created after Feb 2021), then the default server location inherited from the the sbt-sonatype plugin will not work, and you should also include the following overrides in your publishing settings

ThisBuild / sonatypeCredentialHost := "s01.oss.sonatype.org"
sonatypeRepository := "https://s01.oss.sonatype.org/service/local"

GPG

Next, create a fresh gpg key that you will share with GitHub Actions and only use for this project.

gpg --gen-key
  • For real name, you can use anything. For example, this repository uses "sbt-ci-release bot".
  • For email, use your own email address
  • For passphrase, generate a random password with a password manager. This will be the environment variables PGP_PASSPHRASE in your CI. Take note of PGP_PASSPHRASE.

At the end you'll see output like this

pub   rsa2048 2018-06-10 [SC] [expires: 2020-06-09]
      $LONG_ID
uid                      $PROJECT_NAME bot <$EMAIL>

Take note of $LONG_ID, make sure to replace this ID from the code examples below. The ID will look something like (a) 6E8ED79B03AD527F1B281169D28FC818985732D9 or something like (b) A4C9 75D9 9C05 E4C7 2163 4BBD ACA8 EB32 0BFE FE2C (in which case delete the spaces to make it look like (a)). A command like this one should do:

# On UNIX
LONG_ID=6E8ED79B03AD527F1B281169D28FC818985732D9

# On Windows
set LONG_ID=6E8ED79B03AD527F1B281169D28FC818985732D9

Next, copy the public gpg signature

# macOS
gpg --armor --export $LONG_ID | pbcopy
# linux
gpg --armor --export $LONG_ID | xclip
# Windows
gpg --armor --export %LONG_ID%

and post the signature to a keyserver: https://keyserver.ubuntu.com/

  1. Select "Submit Key"
  2. Paste in the exported public key
  3. Click on "Submit Public Key".

Ubuntu Keyserver

or run:

# macOS
gpg --keyserver hkp://keyserver.ubuntu.com --send-key $LONG_ID && \
 gpg --keyserver hkp://pgp.mit.edu --send-key $LONG_ID && \
 gpg --keyserver hkp://pool.sks-keyservers.net --send-key $LONG_ID
# linux
gpg --keyserver hkp://keyserver.ubuntu.com --send-key $LONG_ID && \
 gpg --keyserver hkp://pgp.mit.edu --send-key $LONG_ID && \
 gpg --keyserver hkp://pool.sks-keyservers.net --send-key $LONG_ID
# Windows
gpg --keyserver hkp://keyserver.ubuntu.com --send-key %LONG_ID% && \
 gpg --keyserver hkp://pgp.mit.edu --send-key %LONG_ID% && \
 gpg --keyserver hkp://pool.sks-keyservers.net --send-key %LONG_ID%

Secrets

Next, you'll need to declare four environment variables in your CI. Open the settings page for your CI provider.

  • GitHub Actions:

    Select Settings -> Secrets and variables -> Actions -> New repository secret to add each of the required variables as shown in the next figure:

    github-secrets-2021-01-27

    When complete, your secrets settings should look like the following:

    github-env-vars-2021-01-27

  • Travis CI:

    Make sure that "Build pushed branches" setting is enabled.

Add the following secrets:

  • PGP_PASSPHRASE: The randomly generated password you used to create a fresh gpg key. For Travis Only: If the password contains bash special characters, make sure to escape it by wrapping it in single quotes 'my?pa$$word', see Travis Environment Variables.
  • PGP_SECRET: The base64 encoded secret of your private key that you can export from the command line like here below
# macOS
gpg --armor --export-secret-keys $LONG_ID | base64 | pbcopy
# Ubuntu (assuming GNU base64)
gpg --armor --export-secret-keys $LONG_ID | base64 -w0 | xclip
# Arch
gpg --armor --export-secret-keys $LONG_ID | base64 | sed -z 's;\n;;g' | xclip -selection clipboard -i
# FreeBSD (assuming BSD base64)
gpg --armor --export-secret-keys $LONG_ID | base64 | xclip
# Windows
gpg --armor --export-secret-keys %LONG_ID% | openssl base64

If you try to display the base64 encoded string in the terminal, some shells (like zsh or fish) may include an additional % character at the end, to mark the end of content which was not terminated by a newline character. This does not indicate a problem.

  • SONATYPE_PASSWORD: The password you use to log into https://s01.oss.sonatype.org/ (or https://oss.sonatype.org/ if your Sonatype account was created before February 2021). Alternatively, the password part of the user token if you generated one above. For Travis Only: If the password contains bash special characters, make sure to escape it by wrapping it in single quotes 'my?pa$$word', see Travis Environment Variables.
  • SONATYPE_USERNAME: The username you use to log into https://s01.oss.sonatype.org/ (or https://oss.sonatype.org/ if your Sonatype account was created before 2021). Alternatively, the name part of the user token if you generated one above.
  • (optional) CI_RELEASE: the command to publish all artifacts for stable releases. Defaults to +publishSigned if not provided.
  • (optional) CI_SNAPSHOT_RELEASE: the command to publish all artifacts for a SNAPSHOT releases. Defaults to +publish if not provided.
  • (optional) CI_SONATYPE_RELEASE: the command called to close and promote the staged repository. Useful when, for example, also dealing with non-sbt projects to change to sonatypeReleaseAll. Defaults to sonatypeBundleRelease if not provided.

GitHub Actions

Run the following command to install the same release.yml script that is used to release this repository.

mkdir -p .github/workflows && \
  curl -L https://raw.githubusercontent.com/sbt/sbt-ci-release/main/.github/workflows/release.yml > .github/workflows/release.yml

Commit the file and merge into main.

Travis

Skip this step if you're using GitHub Actions. > Unless you have a specific reason to use Travis, we recommend using GitHub Actions because > it's easier to configure.

Next, update .travis.yml to trigger ci-release on successful merge into master and on tag push. There are many ways to do this, but I recommend using Travis "build stages". It's not necessary to use build stages but they make it easy to avoid publishing the same module multiple times from parallel jobs.

  • First, ensure that git tags are always fetched so that sbt-dynver can pick up the correct version
before_install:
  - git fetch --tags
  • Next, define test and release build stages
stages:
  - name: test
  - name: release
    if: ((branch = master AND type = push) OR (tag IS present)) AND NOT fork
  • Lastly, define your build matrix with ci-release at the bottom, for example:
jobs:
  include:
    # stage="test" if no stage is specified
    - name: compile
      script: sbt compile
    - name: formatting
      script: ./bin/scalafmt --test
    # run ci-release only if previous stages passed
    - stage: release
      script: sbt ci-release

Notes:

  • if we use after_success instead of build stages, we would run ci-release after both formatting and compile. As long as you make sure you don't publish the same module multiple times, you can use any Travis configuration you like
  • the name: compile part is optional but it makes it easy to distinguish different jobs in the Travis UI

build__48_-sbt-ci-release-_travis_ci

Git

We're all set! Time to manually try out the new setup

  • Open a PR and merge it to watch the CI release a -SNAPSHOT version
  • Push a tag and watch the CI do a regular release
git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0

Note that the tag version MUST start with v.

It is normal that something fails on the first attempt to publish from CI. Even if it takes 10 attempts to get it right, it's still worth it because it's so nice to have automatic CI releases. If all is correctly setup, your Travis jobs page will look like this:

screen shot 2018-06-23 at 15 48 43

Enjoy 👌

FAQ

How do I disable publishing in certain projects?

Add the following to the project settings (works only in sbt 1)

publish / skip := true

How do I publish cross-built projects?

Make sure that projects that compile against multiple Scala versions declare the crossScalaVersions setting in build.sbt, for example

lazy val core = project.settings(
  ...
  crossScalaVersions := List("2.13.1", "2.12.10", "2.11.12")
)

The command +publishSigned (default value for CI_RELEASE) will then publish that project for 2.11, 2.12 and 2.13.

How do I publish cross-built Scala.js projects?

If you publish for multiple Scala.js versions, start by disabling publishing of the non-JS projects when the SCALAJS_VERSION environment variable is defined.

// build.sbt
+ val customScalaJSVersion = Option(System.getenv("SCALAJS_VERSION"))
lazy val myLibrary = crossProject(JSPlatform, JVMPlatform)
  .settings(
    // ...
  )
+  .jvmSettings(
+    skip.in(publish) := customScalaJSVersion.isDefined
+  )

Next, add an additional ci-release step in your CI config to publish the custom Scala.js version

// .travis.yml
  sbt ci-release
+ SCALAJS_VERSION=0.6.31 sbt ci-release

Can I depend on Maven Central releases immediately?

Yes! As soon as CI "closes" the staging repository you can depend on those artifacts with

resolvers ++= Resolver.sonatypeOssRepos("staging")

Use this instead if your Sonatype account was created after February 2021

resolvers +=
  "Sonatype OSS Releases" at "https://s01.oss.sonatype.org/content/repositories/releases"

(optional) Use the coursier command line interface to check if a release was successful without opening sbt

coursier fetch com.github.sbt:scalafmt-cli_2.12:1.5.0 -r sonatype:public

Use -r https://s01.oss.sonatype.org/content/repositories/releases instead if your Sonatype account was created after February 2021.

How do I depend on the SNAPSHOT releases?

Add the following setting

resolvers += Resolver.sonatypeRepo("snapshots")

or

resolvers +=
  "Sonatype OSS Snapshots" at "https://s01.oss.sonatype.org/content/repositories/snapshots"

if your Sonatype account was created after February 2021.

(optional) With coursier you can do the same thing with -r sonatype:snapshots

coursier fetch com.github.sbt:scalafmt-cli_2.12:1.5.0-SNAPSHOT -r sonatype:snapshots

Use -r https://s01.oss.sonatype.org/content/repositories/snapshots instead if your Sonatype account was created after February 2021.

What about other CIs environments than Travis?

You can try sbt-release-early.

Alternatively, the source code for sbt-ci-release is only ~50 loc, see CiReleasePlugin.scala. You can copy-paste it to project/ of your build and tweak the settings for your environment.

Does sbt-ci-release work for sbt 0.13?

Yes, but the plugin is not released for sbt 0.13. The plugin source code is a single file which you can copy-paste into project/CiReleasePlugin.scala of your 0.13 build. Make sure you also addSbtPlugin(sbt-dynver + sbt-sonatype + sbt-gpg + sbt-git).

How do I publish sbt plugins?

You can publish sbt plugins to Maven Central like a normal library, no custom setup required. It is not necessary to publish sbt plugins to Bintray.

java.io.IOException: secret key ring doesn't start with secret key tag: tag 0xffffffff

  • Make sure you exported the correct LONG_ID for the gpg key.
  • Make sure the base64 exported secret GPG key is a single line (not line wrapped). If you use the GNU coreutils base64 (default on Ubuntu), pass in the -w0 flag to disable line wrapping.

java.io.IOException: PUT operation to URL https://s01.oss.sonatype.org/content/repositories/snapshots 400: Bad Request

This error happens when you publish a non-SNAPSHOT version to the snapshot repository. If you pushed a tag, make sure the tag version number starts with v. This error can happen if you tag with the version 0.1.0 instead of v0.1.0.

java.io.IOException: Access to URL was refused by the server: Unauthorized

Make sure that SONATYPE_PASSWORD uses proper escaping if it contains special characters as documented on Travis Environment Variables.

Failed: signature-staging, failureMessage:Missing Signature:

Make sure to upgrade to the latest sbt-ci-release, which could fix this error. This failure can happen in case you push a git tag immediately after merging a branch into master. A manual workaround is to log into https://s01.oss.sonatype.org/ (or https://oss.sonatype.org/ if your Sonatype account was created before February 2021) and drop the failing repository from the web UI. Alternatively, you can run sonatypeDrop <staging-repo-id> from the sbt shell instead of using the web UI.

How do I create release notes? Can they be automatically generated?

We think that the creation of release notes should not be fully automated because commit messages don't often communicate the end user impact well. You can use Release Drafter github app (or the Github Action) to help you craft release notes.

My build suddenly fails with [info] gpg: no default secret key: No secret key

Make sure your pgp key did not expire. If it expired you have to change the expiry date and reupload it. See: https://github.com/sbt/sbt-ci-release#gpg.

Adopters

Below is a non-exhaustive list of projects using sbt-ci-release. Don't see your project? Add it in a PR!

Alternatives

There exist great alternatives to sbt-ci-release that may work better for your setup.

  • sbt-ci-release-early: very similar to sbt-ci-release except doesn't use SNAPSHOT versions.
  • sbt-release-early: additionally supports publishing to Bintray and other CI environments than Travis.
  • sbt-rig: additionally supporting publishing code coverage reports, managing test dependencies and publishing docs.

The biggest difference between these and sbt-ci-release wrt to publishing is the base64 encoded PGP_SECRET variable. I never managed to get the encrypted files and openssl working.

More Repositories

1

sbt

sbt, the interactive build tool
Scala
4,685
star
2

sbt-native-packager

sbt Native Packager
Scala
1,590
star
3

sbt-dependency-graph

sbt plugin to create a dependency graph for your project
Scala
1,241
star
4

sbt-jmh

"Trust no one, bench everything." - sbt plugin for JMH (Java Microbenchmark Harness)
Scala
783
star
5

sbt-eclipse

Plugin for sbt to create Eclipse project definitions
Scala
719
star
6

sbt-release

A release plugin for sbt
Scala
640
star
7

sbt-buildinfo

I know this because build.sbt knows this.
Scala
546
star
8

sbt-web

Library for building sbt plugins for the web
Scala
366
star
9

sbt-git

A git plugin for sbt
Scala
343
star
10

zinc

Scala incremental compiler library, used by sbt and other build tools
Scala
328
star
11

docker-sbt

Official sbt docker images
Dockerfile
313
star
12

sbt-dynver

An sbt plugin to dynamically set your version from git
Scala
297
star
13

sbt-onejar

Packages your project using One-JAR™
Scala
267
star
14

sbt-scalariform

sbt plugin adding support for source code formatting using Scalariform
Scala
258
star
15

sbt-fresh

sbt-plugin to create an opinionated fresh sbt project
Scala
233
star
16

sbt-github-actions

An sbt plugin which makes it easier to build with GitHub Actions
Scala
194
star
17

sbt-header

sbt-header is an sbt plugin for creating file headers, e.g. copyright headers
Scala
186
star
18

sbt-bintray

fresh packages delivered from your sbt console
Scala
179
star
19

sbt-protobuf

sbt plugin for compiling protobuf files
Scala
174
star
20

sbt-site

Site generation for sbt
Scala
173
star
21

sbt-start-script

SBT Plugin to create a "start" script to run the program
Scala
144
star
22

sbt-pgp

PGP plugin for sbt
Scala
141
star
23

sbt-groll

sbt plugin to roll the Git history
Scala
133
star
24

junit-interface

Implementation of sbt's test interface for JUnit
Java
132
star
25

sbt-unidoc

sbt plugin to create a unified Scaladoc or Javadoc API document across multiple subprojects.
Scala
124
star
26

sbt-jni

SBT Plugin to ease working with JNI
Scala
123
star
27

sbt-jacoco

an sbt plugin for JaCoCo Code Coverage
Scala
123
star
28

sbt-projectmatrix

Scala
118
star
29

sbt-boilerplate

sbt plugin for generating scala.Tuple/Function related boilerplate code
Scala
109
star
30

sbt-proguard

Proguard sbt plugin
Scala
98
star
31

sbt-atmos

sbt plugin for running Typesafe Console in development
Scala
98
star
32

sbt-launcher-package

Packaging for sbt so you can run it.
Scala
89
star
33

sbt-dirty-money

clean Ivy2 cache
Scala
88
star
34

sbt-license-report

Report on licenses used in an sbt project.
Scala
86
star
35

website

The source for scala-sbt.org
Scala
77
star
36

sbt-doge

sbt plugin to aggregate tasks across subprojects and their crossScalaVersions
Scala
77
star
37

sbt-pom-reader

Translates xml -> awesome. Maven-ish support for sbt.
Scala
76
star
38

sbt-remote-control

Create and manage sbt process using unicorns and forks
Scala
74
star
39

sbt-aspectj

AspectJ sbt plugin
Scala
72
star
40

sbt-scalabuff

SBT plugin which generate case classes and support for serialization from Google Protocol Buffer definitions using ScalaBuff
Scala
72
star
41

contraband

http://www.scala-sbt.org/contraband/
Scala
67
star
42

sbt-s3

sbt-s3 is a simple sbt plugin to manipulate objects on Amazon S3
Scala
63
star
43

sbt-multi-jvm

Multi-JVM testing in sbt
Scala
56
star
44

sbt-javaagent

sbt plugin for adding java agents to projects
Scala
53
star
45

sbt-paradox-material-theme

Material Design theme for Paradox
StringTemplate
51
star
46

sbt-cpd

Copy & Paste Detector plugin using PMD for sbt.
Scala
48
star
47

sbt-osgi

sbt plugin for creating OSGi bundles
Scala
47
star
48

sbt-man

Looks up scaladoc.
Scala
46
star
49

sbt-findbugs

FindBugs static analysis plugin for sbt.
Scala
46
star
50

librarymanagement

librarymanagement module for sbt
Scala
44
star
51

sbt-less

Scala
42
star
52

ipcsocket

IPC: Unix Domain Socket and Windows Named Pipes for Java
Java
42
star
53

launcher

The sbt launcher as its own project. Can launch any ivy/maven published project with a main class, with some fancy features.
Scala
41
star
54

io

IO module for sbt
Scala
40
star
55

sbt-js-engine

Support for sbt plugins that use JavaScript
Scala
40
star
56

sbt-autoversion

Scala
36
star
57

sbt-avro

sbt plugin for compiling Avro schemas, similar to sbt-protobuf
Scala
32
star
58

sbt-digest

sbt-web plugin for checksum files
Scala
32
star
59

sbt-jupiter-interface

Implementation of SBT's test interface for JUnit Jupiter
Java
31
star
60

sbt-slash

unified slash syntax for both shell and build.sbt
Scala
29
star
61

sbt-java-formatter

An sbt plugin for formating Java code
Scala
28
star
62

sbt-gzip

sbt-web plugin for gzipping assets
Scala
25
star
63

sbt-unique-version

emulates Maven's uniqueVersion snapshots
Scala
24
star
64

sbt-pull-request-validator

Plugin that optimizes pull request validation to only validate sub projects that have changed
Scala
24
star
65

sbt.github.com

See https://github.com/sbt/website for the source
HTML
22
star
66

sbt-duplicates-finder

Find classes and resources conflicts in your build
Scala
22
star
67

sbt-autoplugin.g8

giter8 template for sbt 0.13.5+ AutoPlugin
Scala
20
star
68

sbt-cucumber

Cucumber plugin for SBT.
Scala
20
star
69

sbt-jcstress

Trust no-one, and especially not memory visibility.
HTML
19
star
70

adept

adept helps you find, declare, and download dependencies. http://groups.google.com/group/adept-dev/
18
star
71

sbt-sriracha

Scala
17
star
72

sbt-mocha

SBT plugin for running mocha JavaScript unit tests on node
Scala
17
star
73

sbt-multi-release-jar

Support for JDK9's Multi Release JAR Files (JEP 238)
Scala
17
star
74

sbt-xjc

SBT plugin to compile an XML Schema with XJC
Scala
15
star
75

util

util modules for sbt
Scala
15
star
76

sbt-export-repo

exports your dependency graph to a preloaded local repository
Scala
15
star
77

sbt-nocomma

sbt-nocomma reduces commas from your build.sbt.
Scala
13
star
78

serialization

serialization facility for sbt
Scala
13
star
79

sbt-maven-resolver

An sbt plugin to resolve dependencies using Aether
Scala
12
star
80

sbt-core-next

sbt APIs targeted for eventual inclusion in sbt core
Scala
12
star
81

sbt-houserules

House rules for sbt modules.
Scala
12
star
82

sbt-pamflet

sbt plugin to run Pamflet (and Pamflet plugin to run sbt)
Scala
11
star
83

sbt-sdlc

Scaladoc link checker for sbt
Scala
11
star
84

sbt-appbundle

A plugin for the simple-build-tool to create an OS X application bundle.
Scala
10
star
85

bintry

your packages, delivered fresh
Scala
10
star
86

sbt-fmpp

FreeMarker Scala/Java Templating Plugin for SBT
Scala
9
star
87

sbt-ynolub

Scala
9
star
88

sbt-testng

Implementation of the sbt testing interface for TestNG, bundled with an sbt plug-in for convenience.
Scala
9
star
89

sbt-concat

sbt-web plugin for concatenating web assets
Scala
8
star
90

sbt-ant

SBT plug-in to call Ant targets from within SBT builds
Scala
7
star
91

sbtn-dist

Shell
6
star
92

sbt-community-plugins

All community plugins that opt into an uber-build
Scala
6
star
93

sbt-vimquit

an sbt plugin that adds :q command.
Scala
5
star
94

helloworld-one

An example build for sbt 1.0.0.
Scala
5
star
95

sbt-giter8-resolver

Scala
5
star
96

sbt-sequential

adds sequential tasks to sbt
Scala
4
star
97

sbt-scalashim

generates sys.error.
Scala
4
star
98

sbt-experimental

Experimental APIs to fix rough edges in sbt
Scala
3
star
99

sbt-web-build-base

Scala
3
star
100

sbt-validator

Builds sbt 1.0.x against recent versions of the sbt modules
Shell
3
star