From 1a4ea597c2f7f738c67f2b65d62f66f2c3292dc6 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Thu, 18 Jul 2019 14:30:59 -0700 Subject: [PATCH] add tag-based publishing infra --- .travis.yml | 11 +++++- README.md | 19 ++++++++--- admin/README.md | 68 +++++++++++++++++++++++++++++++++++++ admin/build.sh | 48 ++++++++++++++++++++++++++ admin/encryptEnvVars.sh | 11 ++++++ admin/genKeyPair.sh | 41 ++++++++++++++++++++++ admin/gpg.sbt | 1 + admin/publish-settings.sbt | 8 +++++ admin/pubring.asc | 18 ++++++++++ admin/secring.asc.enc | Bin 0 -> 1888 bytes project/plugins.sbt | 2 -- 11 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 admin/README.md create mode 100755 admin/build.sh create mode 100755 admin/encryptEnvVars.sh create mode 100755 admin/genKeyPair.sh create mode 100644 admin/gpg.sbt create mode 100644 admin/publish-settings.sbt create mode 100644 admin/pubring.asc create mode 100644 admin/secring.asc.enc diff --git a/.travis.yml b/.travis.yml index 79afb79..79b2bc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,16 @@ scala: - 2.13.0 script: - - sbt ++$TRAVIS_SCALA_VERSION test + - admin/build.sh + +env: + global: + # PGP_PASSPHRASE + - secure: "NAYlvLQD1OiF+B8NvN+l1Lh0a2xa9FYFfA7LVHt1FXkri6wM/44oVuLF2H7BQTHczFN4754lAR5nrXrBccX1pa4BFmdNLu/nzZIjzjMxz5rFJRcK3nsycJPPUSY6mh5jBP5mR+hyW1zngQPGqCMmwAPP6pANaAztKh34DMSCcdRWb9Gfz6+IL0whCUywYk6LcXBfpD+H0u2ahGUM5ZTWWqqyTDiYmGIhfkXShUZ7oRYNgxffK3BbC5c3UztOTefHMiSCVgqnqNxmFCaGijtm6P1lxW4ebXrklVdb8/Z2AOrJxjV2+Itytb/8w7ukQvYUaPwBoyJYbN0glicMXoYwXKaJ0Rs7VxLFShUQGzDuQFzn5mcjn6r46Gs7aPYC0WTRW6Tx8aaaie7kV+w1zwIx1FrK4OpGaCKGQc73sEUng9EPcVZCbBNS5MNuF/yCfyYN+tSrC7Ms7KzQUwk1aoabEctEqL/Nax8LwayuBBFGrOQnOI9Rt6IxFAze6tJShkcNrZeOp6P/2eCanipHqH18lV3gNr7mKmJL1kTiBdMHo41S/DumNblOz1n5pVOBBLIOjD2Q55uDHAWUPXLbRa+BMtGrmbY2IHIUQPZNKTvnZ5PzoOezP2nSKANUC0V4pN7gVGOmZ/2iPJ7/itdU1tqlQFGRPJvTAzRtsXbPhynEqqw=" + # SONA_USER + - secure: "Uc+tOT5E5FEQwLx4ZXZO1Oum1HAhMbvCWpKpkReqdsyb+xBdMbJkt43o8jvM/2WNVMcijEku87o5yWWa/fRDfqBg4GCuwnjUYu/3S0Lyxso8Mgmlcn6khmi09inOvAMVpCdBjvr+krJG1kXgxO62qA3IM0FU9z06Kcngz8F4YhnSGBv2HkOI/+9UHjQeex7tSUSFZi8itnEIN+gK4oWLVItyo0MbH4539BeJyoq/+e70xNxolLFHpVhruBQssg8MS60C5rajo7FXo1BODv+SIR+d1UZ6z8sl2iFU2psijej39nYHzmbxuM9P5Twozs38Rq7g4CM5aFLebna8VZoO6zZtM4PIAyiExkWWILQknrZEhHSded6l73GDeX+eoIigvYNxxAgXMh+MJll1i+XEySLjku8NvarQJ8c09x4S/Rjz1CBEfvlAhM+f117PqVsB87JBnsfE7CABfusJ2wqBpFf9pq9DA3E62XSEniWTIzow37YSR7opRv6wvHzuGrO6OeadIN1P2hb/FDiXDBnqG4xtGUFx81FM0dl9jV97kYiXoaqTwjT0j3d1MBGiN7IzeHxLbczMWA9mvvXtIeOxa73mph3grKKXiRqf/U+455oEIbCObEudjI7zXbjhXGeoVb+OqU7t5Beo+0Lg3H0hyntCsewops/h52lTmgsg5Hw=" + # SONA_PASS + - secure: "ggXFZBlzV5ek/rBaE9lrEZlAIfUrv4XDJ4OrP8daMrJxmwkXtoSbcB3z4VgqqWKzAzW89CcU1IiojzDbe/het3xEX4qxdz5Wt05/E+WOgbek528kelwMxq12XRe6xaCVfG+y8OISPgq1q3vKoO/xYGVbK3D6hSD+cjojEXyPpjAfrVSUof06aNPFPQeLX9exgu9zrxkJJm01PbTh19vQk4Ojc++oEmpF7HLD1CF1m7AlW0U2Rba+syivpj9Ray3Z9vu0TnFL06r4TiwZruwcXTLrWUqumFI0r5mhaY6SNH7bqttu+3RPIOdkUGxIeGlkDi3xopt7r2aEkhOKvjRXapW0e/CWmUo1J+NnlIumxrldi4n0iiJGVEvY4Krx/HGZe0wCVTh4vDNOllTGdFmkkxN6WoaHALgj3QNM3XLjvvUu3VcT+QNtsVIvgUDesrtos8zCKczzdhL/d4BMiIg7SFfA33S3vx8BeczLBqddrx+yLSPzfheKrHW7g76EAEyN26vE2/2/GRlMOlG8Lmu8rXBfIPsK9T/ztfE1CxaTW5EsMSrxO2+O/bvAa6DY0R79KkHf7LDI+azzP2NwYx8anM9WlMTp4EbawI/KGZRilWYtJ3Q3y5EQERsrP71W35dKqiBFMPdspS+lTS9hGtso08n7cR2MwTbRjoXVRcWfJ/I=" before_cache: - find $HOME/.sbt -name "*.lock" | xargs rm diff --git a/README.md b/README.md index 4f64081..e47a5ba 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# Scala Collection Contrib +# scala-collection-contrib -This module provides extra features to the Scala standard collections. +This module provides various additions to the Scala 2.13 standard collections. -## New Collection Types +## New collection types - `MultiSet` (both mutable and immutable) - `SortedMultiSet` (both mutable and immutable) - `MultiDict` (both mutable and immutable) - `SortedMultiDict` (both mutable and immutable) -## New Operations +## New operations The new operations are provided via an implicit enrichment. You need to add the following import to make them available: @@ -27,3 +27,14 @@ The following operations are provided: - `zipByKey` / `join` / `zipByKeyWith` - `mergeByKey` / `fullOuterJoin` / `mergeByKeyWith` / `leftOuterJoin` / `rightOuterJoin` +## Maintenance status + +This module is community-maintained. If you are interested in +participating, please jump right in on issues and pull requests. + +## Releasing + +As with other Scala standard modules, build and release infrastructure +is provided by the +[sbt-scala-module](https://github.com/scala/sbt-scala-module/) sbt +plugin. diff --git a/admin/README.md b/admin/README.md new file mode 100644 index 0000000..2659187 --- /dev/null +++ b/admin/README.md @@ -0,0 +1,68 @@ +## Tag Driven Releasing + +### Initial setup for the repository + +To configure tag driven releases from Travis CI. + + 1. Generate a key pair for this repository with `./admin/genKeyPair.sh`. + Edit `.travis.yml` and `admin/build.sh` as prompted. + 1. Publish the public key to https://pgp.mit.edu + 1. Store other secrets as encrypted environment variables with `./admin/encryptEnvVars.sh`. + Edit `.travis.yml` as prompted. + 1. Edit `.travis.yml` to use `./admin/build.sh` as the build script, + and edit that script to use the tasks required for this project. + Ensure that `RELEASE_COMBO` is `true` for build matrix combinations + that should be released to sonatype (when building a tag). + +It is important to add comments in `.travis.yml` to identify the name +of each environment variable encoded in a `secure` section. + +After these steps, your `.travis.yml` should contain config of the form: + +``` +language: scala + +jdk: + - openjdk8 + +scala: + - 2.11.12 + - 2.12.6 + +env: + global: + # PGP_PASSPHRASE + - secure: "XXXXXX" + # SONA_USER + - secure: "XXXXXX" + # SONA_PASS + - secure: "XXXXXX" + +script: admin/build.sh + +notifications: + email: + - a@b.com +``` + +If Sonatype credentials change in the future, step 3 can be repeated +without generating a new key. + +### Testing + + 1. Follow the release process below to create a dummy release (e.g., `v0.1.0-TEST1`). + Confirm that the release was staged to Sonatype but do not release it to Maven + central. Instead, drop the staging repository. + +### Performing a release + + 1. Create a GitHub "Release" with a corresponding tag (e.g., `v0.1.1`) via the GitHub + web interface. + 1. The release will be published using the Scala and JVM version combinations specified + in the travis build matrix where `[ "$RELEASE_COMBO" = "true" ]`. + - If you need to release against a different Scala version, create a new commit that modifies + `.travis.yml` and push a new tag, e.g., `v1.2.3#2.13.0-M5`. The suffix after `#` is ignored. + 1. Travis CI will schedule a build for this release. Review the build logs. + 1. Log into https://oss.sonatype.org/ and identify the staging repository. + 1. Sanity check its contents. + 1. Release staging repository to Maven and send out release announcement. diff --git a/admin/build.sh b/admin/build.sh new file mode 100755 index 0000000..6235054 --- /dev/null +++ b/admin/build.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +# Builds of tagged revisions are published to sonatype staging. + +# Travis runs a build on revisions, including on new tags. +# Builds for a tag have TRAVIS_TAG defined, which we use for identifying tagged builds. +# Checking the local git clone would not work because git on travis does not fetch tags. + +# The version number to be published is extracted from the tag, e.g., v1.2.3 publishes +# version 1.2.3 on all combinations of the travis matrix where `[ "$RELEASE_COMBO" = "true" ]`. + +# In order to build a previously released version against a new (binary incompatible) Scala release, +# a new commit that modifies (and prunes) the Scala versions in .travis.yml needs to be added on top +# of the existing tag. Then a new tag can be created for that commit, e.g., `v1.2.3#2.13.0-M5`. +# Everything after the `#` in the tag name is ignored. + +if [[ "$TRAVIS_JDK_VERSION" == "openjdk8" ]]; then + RELEASE_COMBO=true; +fi + +verPat="[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9-]+)?" +tagPat="^v$verPat(#.*)?$" + +if [[ "$TRAVIS_TAG" =~ $tagPat ]]; then + tagVer=${TRAVIS_TAG} + tagVer=${tagVer#v} # Remove `v` at beginning. + tagVer=${tagVer%%#*} # Remove anything after `#`. + publishVersion='set every version := "'$tagVer'"' + + if [ "$RELEASE_COMBO" = "true" ]; then + currentJvmVer=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | sed 's/^1\.//' | sed 's/[^0-9].*//') + echo "Releasing $tagVer with Scala $TRAVIS_SCALA_VERSION on Java version $currentJvmVer." + + publishTask="publishSigned" + + cat admin/gpg.sbt >> project/plugins.sbt + cp admin/publish-settings.sbt . + + # Copied from the output of genKeyPair.sh + K=$encrypted_6b8d67feaab7_key + IV=$encrypted_6b8d67feaab7_iv + openssl aes-256-cbc -K $K -iv $IV -in admin/secring.asc.enc -out admin/secring.asc -d + fi +fi + +sbt "++$TRAVIS_SCALA_VERSION" "$publishVersion" "clean" "test" "publishLocal" "$publishTask" diff --git a/admin/encryptEnvVars.sh b/admin/encryptEnvVars.sh new file mode 100755 index 0000000..b625667 --- /dev/null +++ b/admin/encryptEnvVars.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Encrypt sonatype credentials so that they can be +# decrypted in trusted builds on Travis CI. +# +set -e + +read -s -p 'SONA_USER: ' SONA_USER +travis encrypt SONA_USER="$SONA_USER" +read -s -p 'SONA_PASS: ' SONA_PASS +travis encrypt SONA_PASS="$SONA_PASS" diff --git a/admin/genKeyPair.sh b/admin/genKeyPair.sh new file mode 100755 index 0000000..17db3f3 --- /dev/null +++ b/admin/genKeyPair.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Generates a key pair for this repository to sign artifacts. +# Encrypt the private key and its passphrase in trusted builds +# on Travis CI. +# +set -e + +# Based on https://gist.github.com/kzap/5819745: +function promptDelete() { + if [[ -f "$1" ]]; then + echo About to delete $1, Enter for okay / CTRL-C to cancel + read + rm "$1" + fi +} +for f in admin/secring.asc.enc admin/secring.asc admin/pubring.asc; do promptDelete "$f"; done + +echo Generating key pair. Please enter 1. repo name 2. scala-internals@googlegroups.com, 3. a new passphrase +echo Be careful when using special characters in the passphrase, see http://docs.travis-ci.com/user/encryption-keys/#Note-on-escaping-certain-symbols +cp admin/gpg.sbt project +sbt 'set pgpReadOnly := false' \ + 'set pgpPublicRing := file("admin/pubring.asc")' \ + 'set pgpSecretRing := file("admin/secring.asc")' \ + 'pgp-cmd gen-key' +rm project/gpg.sbt + +echo ============================================================================================ +echo Encrypting admin/secring.asc. Update K and IV variables in admin/build.sh accordingly. +echo ============================================================================================ +travis encrypt-file admin/secring.asc +rm admin/secring.asc +mv secring.asc.enc admin + +echo ============================================================================================ +echo Encrypting environment variables. Add each to a line in .travis.yml. Include a comment +echo with the name of the corresponding variable +echo ============================================================================================ +read -s -p 'PGP_PASSPHRASE: ' PGP_PASSPHRASE +travis encrypt PGP_PASSPHRASE="$PGP_PASSPHRASE" + diff --git a/admin/gpg.sbt b/admin/gpg.sbt new file mode 100644 index 0000000..3b55e21 --- /dev/null +++ b/admin/gpg.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2-1") // only added when publishing, see build.sh diff --git a/admin/publish-settings.sbt b/admin/publish-settings.sbt new file mode 100644 index 0000000..026c6ee --- /dev/null +++ b/admin/publish-settings.sbt @@ -0,0 +1,8 @@ +def env(key: String) = Option(System.getenv(key)).getOrElse("") + +inThisBuild(Seq( + pgpPassphrase := Some(env("PGP_PASSPHRASE").toArray), + pgpPublicRing := file("admin/pubring.asc"), + pgpSecretRing := file("admin/secring.asc"), + credentials += Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", env("SONA_USER"), env("SONA_PASS")) +)) diff --git a/admin/pubring.asc b/admin/pubring.asc new file mode 100644 index 0000000..ac1349c --- /dev/null +++ b/admin/pubring.asc @@ -0,0 +1,18 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: BCPG v1.51 + +mQENBF0w4ZMBCACLX2RqR9L5J9wti2G8Hgi0XktuUtaHighmKT31tQgQf4RleHsR +kd+cVKaop623+LTf+8HHBquB2ZbIGg0gnyFUluPJEIanSYAJbM373snvwkUzU28x +g0KTHWg3HaX+2Yg2TemL2EW6TQYdOpHk7jkxUMxOAIAd+YalEZpGCgEEiKqTTNIt +24sqZHyS8n6rT+RD+PcyQBqRG6eoPRQdjUzNaFcD+SEilpqVlG3I3qAdsdPMI7bi +O2jWVKE38NMemiPweGdAgZrya4a7srg9x5lujlqN3LtzBhwZLolymGYLEQfE2v1v +4Mr4fO2roFpSVkZQSdeqVqfjDHMaz0mY6tUFABEBAAG0O3NjYWxhLWNvbGxlY3Rp +b24tY29udHJpYiA8c2NhbGEtaW50ZXJuYWxzQGdvb2dsZWdyb3Vwcy5jb20+iQEc +BBMBAgAGBQJdMOGTAAoJEJUcb0POSwjJw+sH/AvkB05NR3ojI8880WIceWeFPPHF +ISK9l5KNchBB0+3OwB9w6X2J75MV7F/stNfgYe+meQlxveHNi/z4ULKxhFVMj7JK +ldr2H5rvtxNyLgSL8ljBGPAcHml81SML8J0qNoRPXPkmbnXPdZZ7NPqMGUIbZtCX +40HD5LAjv+q2Q4OERtQpjN9qK0c2pWi2W3JzfUh55adPAoPXSVBIfxImLSdPGKBc +Dj8ugFAqxivUvCQhwa91RkFLL+PefRDvSalPofRXY6P0Vn+gQZm4wgGerp05uEnk +v5ZEO2WrXxffwMsZog6CCFuNgmjJrMkhaAF4/JO/7mlrmpkf6tpXxF+MabA= +=tc/r +-----END PGP PUBLIC KEY BLOCK----- diff --git a/admin/secring.asc.enc b/admin/secring.asc.enc new file mode 100644 index 0000000000000000000000000000000000000000..6e29807b8a8e627ae9c49bcc57aa03892d445a7a GIT binary patch literal 1888 zcmV-m2cP&F!gpb=e?iRpD1&#HRJcbrGrhzpjrOK(pR(K74}{)pZ8^S`e|`3e_U86f zF2 zf!cM377Aa?G|5^lFJ!Oie9UU>YDtsPNn~rF_pkbXp_-RB?OIWo3ZHi*xooYy@Tmz3 zGvdKg7JS;M6v&E2MT7%S*8_n2Hqkek6GrzxlY$EL#rSX0&n!4V{jsZMbm}AZMLYGt>V>}>b0*PDY8bB5XGsev>v%?QR06q)#!8rS)zXEN1NWXLf`TlJ)Jpq1F0V&xp? z$(G%*{IS$!m&XoZd_BxtXRXga>93n1L%7@5y0_|}w>W~)udw=(Sf8|oF+-9GXs^9> z2)%4T$-AR&7Sw5*O6UqI3b`n?w`9Tx1mT2e;t&8%p?i|1uV{t@6Z%fI5MF- z*e!;4v8@8#i+1q=6acG_ZANeiB^DRXP!bi8Vg1em@Py9T(GsKPF4Si#>FLzywEW^e)VHhEjvWO~X20VoxR)Crpr=%w~A!>Dwi z98D%tmrb7MH@-?W{^=fg+e<@iLj$@5xMA~DED5OXbesSs*i4KKG9YfGZE#T^AE)N| zphi5jZ~Y(%wL_1BU^g~SwaQ9qGK;O;HGCWBN&MRdt^MI1?8iTryn`tg(}Eim+Aht@HM=)ZW`avyZux>Azi?o_jA8bzUEt;sO**8VPt`YQNb1laqGAdGiA=pQz~s zc`71U3Zre|p8xBkLw^OM@7p&p%Z2L!_ROY#)tu})AG{p zm?SS&^cM!v#uRMc$F9N%!09QU@4X+2!3#e(b&-T*{RKR-@->))e8P%BF1t1y4>0z@ zIZPi0M2zU++!ztlg;kF!RkP}eR#sqDG_s)zugQlHXZQdjV(eUB@Yvm&I=KQ(sFHq4 z`+M3FCUp_?8N;#6wpu`m;wrc&V{nLRn54D~y)`eiw0BTmcZYM0iUOmUB-PI)Ue|)Q z;7SN!Mf%_!+?dxC^LoN|-FDV@hJbb@oNk1sy{9Gw?YrC#IO8}Kz$Z6PlJGDRpe&Jr z+X2=9Bw$#4cdCs)o7v_8&+wWdW0AdW`<9iI@6By9@~#2vFBL!Vx}E5p51j{yNs%IuGwVx^UzQ*2H8UA$9hM{6$C7gD@p8{8AM#** zxe}a(@EJ#o)C^({a!-BYPik}@Eq`Mn?0<}@WN)~CUj6Gl!{gsXQw-ODo;4HsuW&r@ zfHM!tH)HBQ=Y8Ycfd9VAs;pf6ZDPYb+`jz@bD0^|V22E++JS*P^*_Dq4zPDD?S&#F zD5!MPI`sk&=#Dabf-G^z?baWvb3bnVNGFw_R~+|l&RyQ~}9jr_M>qC literal 0 HcmV?d00001 diff --git a/project/plugins.sbt b/project/plugins.sbt index 2fea6a4..2c32f62 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,3 @@ scalacOptions ++= Seq("-deprecation", "-feature", "-Xfatal-warnings") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2") addSbtPlugin("org.scala-lang.modules" % "sbt-scala-module" % "2.0.0")