There is an sbt concept of state. State is a data structure that contains information about the current sbt run (tasks remaining, generic data, etc). The action part of a command performs work and transforms State.
sbt creates an initial instance of State, in the application entry point, that is then passed through each command.
sbt-sonatype suggests a two-step release process for projects:
publish publishes artifacts to staging repository
sonatypeRelease closes and promotes staging repository
If we run publish without creating a staging repository with sonatypeOpen, artifacts get placed in a staging repository created automatically with the description Implicitly created (auto staging)..
It is not clear to me how this behavior works. sonatypeDefaultResolver seems to require a staging repository to exist so it can generate a URL where we can push artifacts.
A staging repository is either created on the fly, if needed, or just selected.
It seems that if we create a staging repository with sonatypeOpen, that repository ID gets preserved in the State for the remainder of the sbt run.
Right now, sonatypeRelease is failing because multiple staging repositories come back when it makes a call to findTargetRepository(CloseAndPromote, repoID).
My theory is that because sonatypeOpen was never ran, there was never an opportunity to preserve an instance of StagingRepositoryProfile in the State. So, sonatypeRelease passes an empty value for repoID to findTargetRepository, which causes the filter to match every staging repository associated with the staging profile.
It seems like a potential solution is to run sonatypeOpen before publish. This will persist a repository ID in the State so sonatypeRelease can filter for a single repository.
Resolves #106
Checklist
[x] Description of PR is in an appropriate section of the CHANGELOG and grouped with similar changes if possible
Testing Instructions
For testing, I am using sonatypeClose instead of sonatypeRelease, to avoid promoting artifacts to Maven Central. This should be fine, as they both invoke findTargetRepository.
I opened multiple staging repositories:
./sbt ";sonatypeOpen 1; sonatypeOpen 2;"
See that, with a fresh sbt State, you cannot execute sonatypeClose if there are multiple staging repositories:
$ ./sbt sonatypeClose
[error] Multiple repositories are found:
[error] [comazavea-1069] status:open, profile:com.azavea(21dbdcb1c584be) description: 1
[error] [comazavea-1070] status:open, profile:com.azavea(21dbdcb1c584be) description: 2
[error] Specify one of the repository ids in the command line
[error] java.lang.IllegalStateException: Found multiple staging repositories
...
If the previous command had been ;sonatypeOpen 1; sonatypeOpen 2;sonatypeClose, this would have closed the second staging repository.
Next, see that the revised cipublish command is able to execute publish and sonatypeClose despite there being multiple staging repositories:
$ git tag -a 0.5.0
$ git describe
0.5.0
$ ./sbt ";++${SCALA_VERSION:-2.11.12};sonatypeOpen $(date +%s);publish;sonatypeClose"
...
[info] Nexus repository URL: https://oss.sonatype.org/service/local
[info] sonatypeProfileName = com.azavea
[info] Reading staging profiles...
[info] Creating staging repository in profile: com.azavea
[info] Created successfully: comazavea-1073
...
[info] published maml-jvm_2.11 to https://oss.sonatype.org/service/local/staging/deployByRepositoryId/comazavea-1073/com/azavea/geotrellis/maml-jvm_2.11/0.5.0/maml-jvm_2.11-0.5.0.pom
[info] published maml-jvm_2.11 to https://oss.sonatype.org/service/local/staging/deployByRepositoryId/comazavea-1073/com/azavea/geotrellis/maml-jvm_2.11/0.5.0/maml-jvm_2.11-0.5.0.jar
[info] published maml-jvm_2.11 to https://oss.sonatype.org/service/local/staging/deployByRepositoryId/comazavea-1073/com/azavea/geotrellis/maml-jvm_2.11/0.5.0/maml-jvm_2.11-0.5.0-javadoc.jar.asc
[info] published maml-jvm_2.11 to https://oss.sonatype.org/service/local/staging/deployByRepositoryId/comazavea-1073/com/azavea/geotrellis/maml-jvm_2.11/0.5.0/maml-jvm_2.11-0.5.0.pom.asc
[success] Total time: 23 s, completed Jun 14, 2019 12:55:21 PM
[info] Nexus repository URL: https://oss.sonatype.org/service/local
[info] sonatypeProfileName = com.azavea
[info] Reading staging repository profiles...
[info] Reading staging profiles...
[info] Closing staging repository [comazavea-1073] status:open, profile:com.azavea(21dbdcb1c584be) description: 1560531269
[info] Activity open started:2019-06-14T16:54:46.561Z, stopped:2019-06-14T16:54:56.315Z
[info] repositoryCreated: id:comazavea-1073, user:azaveaci, ip:removed_because_public_repo
[info] Activity close started:2019-06-14T16:55:31.565Z, stopped:
[info] Evaluate: id:5e9e8e6f8d20a3, rule:sources-staging
[info] Evaluate: pom-staging
[info] Passed: pom-staging
[info] Evaluate: checksum-staging
[info] Passed: checksum-staging
[info] Evaluate: javadoc-staging
[info] Passed: javadoc-staging
[info] Evaluate: signature-staging
[info] Passed: signature-staging
[info] Evaluate: no-traversal-paths-in-archive-file
[info] Passed: no-traversal-paths-in-archive-file
[info] Evaluate: profile-target-matching-staging
[info] Passed: profile-target-matching-staging
[info] Evaluate: sources-staging
[info] Passed: sources-staging
[info] Passed: id:5e9e8e6f8d20a3
[[info] email: to:systems@azavea.com
[info] repositoryClosed: id:comazavea-1073
[info] Closed successfully
[info] Set current project to root (in build file:/Users/rbreslow/Projects/maml/)
In order to test, you will need:
Sonatype credentials set in your environment
The GeoTrellis private signing subkey in your GPG keyring (and GPG_KEY_ID set)
DM me on Slack if you'd like help setting up these credentials.
Overview
There is an sbt concept of state.
State
is a data structure that contains information about the current sbt run (tasks remaining, generic data, etc). The action part of a command performs work and transformsState
.sbt creates an initial instance of
State
, in the application entry point, that is then passed through each command.sbt-sonatype suggests a two-step release process for projects:
publish
publishes artifacts to staging repositorysonatypeRelease
closes and promotes staging repositoryIf we run
publish
without creating a staging repository withsonatypeOpen
, artifacts get placed in a staging repository created automatically with the descriptionImplicitly created (auto staging).
.It is not clear to me how this behavior works.
sonatypeDefaultResolver
seems to require a staging repository to exist so it can generate a URL where we can push artifacts.Sonatype's Configuring Your Project for Deployment docs say:
It seems that if we create a staging repository with
sonatypeOpen
, that repository ID gets preserved in theState
for the remainder of the sbt run.Right now,
sonatypeRelease
is failing because multiple staging repositories come back when it makes a call tofindTargetRepository(CloseAndPromote, repoID)
.My theory is that because
sonatypeOpen
was never ran, there was never an opportunity to preserve an instance ofStagingRepositoryProfile
in theState
. So,sonatypeRelease
passes an empty value forrepoID
tofindTargetRepository
, which causes the filter to match every staging repository associated with the staging profile.See:
sonatypeRelease
- https://github.com/xerial/sbt-sonatype/blob/465d4688944de884b612396ec199cdb9b6518138/src/main/scala/xerial/sbt/Sonatype.scala#L274-L285findTargetRepository
- https://github.com/xerial/sbt-sonatype/blob/465d4688944de884b612396ec199cdb9b6518138/src/main/scala/xerial/sbt/Sonatype.scala#L515-L549It seems like a potential solution is to run
sonatypeOpen
beforepublish
. This will persist a repository ID in theState
sosonatypeRelease
can filter for a single repository.Resolves #106
Checklist
Testing Instructions
For testing, I am using
sonatypeClose
instead ofsonatypeRelease
, to avoid promoting artifacts to Maven Central. This should be fine, as they both invokefindTargetRepository
.I opened multiple staging repositories:
See that, with a fresh sbt
State
, you cannot executesonatypeClose
if there are multiple staging repositories:If the previous command had been
;sonatypeOpen 1; sonatypeOpen 2;sonatypeClose
, this would have closed the second staging repository.Next, see that the revised
cipublish
command is able to executepublish
andsonatypeClose
despite there being multiple staging repositories:In order to test, you will need:
GPG_KEY_ID
set)DM me on Slack if you'd like help setting up these credentials.