aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorChristopher Vogt <oss.nsp@cvogt.org>2017-03-04 02:44:02 +0000
committerChristopher Vogt <oss.nsp@cvogt.org>2017-03-04 20:43:13 -0500
commit8d4d1b0f0b984ea39a92094e775e82bbb2bd9863 (patch)
tree0bdb6691931e7ce5c70dcf5bf20da3464dd6fdeb /plugins
parent9df63f9cbe5df707137e36dc0467e8d197ca2836 (diff)
downloadcbt-8d4d1b0f0b984ea39a92094e775e82bbb2bd9863.tar.gz
cbt-8d4d1b0f0b984ea39a92094e775e82bbb2bd9863.tar.bz2
cbt-8d4d1b0f0b984ea39a92094e775e82bbb2bd9863.zip
improve sonatype plugin
- reduce required tasks in favor of using SonatypeLib.copy - improve log messages - automatically release non-snapshots after uploading
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonatype-release/src/SonatypeRelease.scala29
-rw-r--r--plugins/sonatype-release/src/sonatype/HttpUtils.scala2
-rw-r--r--plugins/sonatype-release/src/sonatype/SonatypeHttpApi.scala36
-rw-r--r--plugins/sonatype-release/src/sonatype/SonatypeLib.scala108
-rw-r--r--plugins/sonatype-release/src/sonatype/models.scala4
5 files changed, 70 insertions, 109 deletions
diff --git a/plugins/sonatype-release/src/SonatypeRelease.scala b/plugins/sonatype-release/src/SonatypeRelease.scala
index e53a5a1..5d908f9 100644
--- a/plugins/sonatype-release/src/SonatypeRelease.scala
+++ b/plugins/sonatype-release/src/SonatypeRelease.scala
@@ -17,31 +17,10 @@ import cbt.sonatype.SonatypeLib
* - promotes staging repository to Central repository;
* - drops staging repository after release.
*/
-trait SonatypeRelease extends Publish {
+trait SonatypeRelease extends Publish{
+ protected def sonatypeLib = SonatypeLib(groupId)
- def profileName: String = groupId
+ def publishSonatype = sonatypeLib.publishSigned( publishedArtifacts, releaseFolder )
- def sonatypeServiceURI: String = SonatypeLib.sonatypeServiceURI
-
- def sonatypeSnapshotsURI: String = SonatypeLib.sonatypeSnapshotsURI
-
- def sonatypeCredentials: String = SonatypeLib.sonatypeCredentials
-
- def sonatypePublishSigned: ExitCode = {
- sonatypeLib.sonatypePublishSigned(
- sourceFiles,
- `package` :+ pom,
- groupId,
- artifactId,
- version,
- isSnapshot,
- scalaMajorVersion
- )
- }
-
- def sonatypeRelease: ExitCode =
- sonatypeLib.sonatypeRelease(groupId, artifactId, version)
-
- private def sonatypeLib =
- new SonatypeLib(sonatypeServiceURI, sonatypeSnapshotsURI, sonatypeCredentials, profileName)(lib, logger.log("sonatype-release",_))
+ override def publish = {super.publish; publishSonatype}
}
diff --git a/plugins/sonatype-release/src/sonatype/HttpUtils.scala b/plugins/sonatype-release/src/sonatype/HttpUtils.scala
index 9d23744..737fea9 100644
--- a/plugins/sonatype-release/src/sonatype/HttpUtils.scala
+++ b/plugins/sonatype-release/src/sonatype/HttpUtils.scala
@@ -21,7 +21,7 @@ private[sonatype] object HttpUtils {
conn.setReadTimeout(60000) // 1 minute
conn.setConnectTimeout(30000) // 30 seconds
- headers foreach { case (k,v) =>
+ (Map("User-Agent" -> "CBT build tool") ++ headers) foreach { case (k,v) =>
conn.setRequestProperty(k, v)
}
conn.setRequestMethod(method)
diff --git a/plugins/sonatype-release/src/sonatype/SonatypeHttpApi.scala b/plugins/sonatype-release/src/sonatype/SonatypeHttpApi.scala
index 6c6f4e8..d4163a8 100644
--- a/plugins/sonatype-release/src/sonatype/SonatypeHttpApi.scala
+++ b/plugins/sonatype-release/src/sonatype/SonatypeHttpApi.scala
@@ -12,7 +12,7 @@ import scala.xml.XML
* Publish proccess via HTTP API described here:
* https://support.sonatype.com/hc/en-us/articles/213465868-Uploading-to-a-Staging-Repository-via-REST-API?page=1#comment_204178478
*/
-private final class SonatypeHttpApi(sonatypeURI: String, sonatypeCredentials: String, profileName: String)(log: String => Unit) {
+final class SonatypeHttpApi(sonatypeURI: String, sonatypeCredentials: String, profileName: String)(log: String => Unit) {
import HttpUtils._
private val base64Credentials = new String(Base64.getEncoder.encode(sonatypeCredentials.getBytes))
@@ -20,21 +20,25 @@ private final class SonatypeHttpApi(sonatypeURI: String, sonatypeCredentials: St
// https://oss.sonatype.org/nexus-staging-plugin/default/docs/path__staging_profiles.html
def getStagingProfile: StagingProfile = {
log(s"Retrieving info for profile: $profileName")
- val (_, response) = GET(
- uri = s"$sonatypeURI/staging/profiles",
- headers = Map("Authorization" -> s"Basic $base64Credentials")
- )
+ try{
+ val (_, response) = GET(
+ uri = s"$sonatypeURI/staging/profiles",
+ headers = Map("Authorization" -> s"Basic $base64Credentials")
+ )
- val currentProfile = (XML.loadString(response) \\ "stagingProfile" find { profile =>
- (profile \ "name").headOption.exists(_.text == profileName)
- }).getOrElse(throw new Exception(s"Failed to get profile with name: $profileName"))
+ val currentProfile = (XML.loadString(response) \\ "stagingProfile" find { profile =>
+ (profile \ "name").headOption.exists(_.text == profileName)
+ }).getOrElse(throw new Exception(s"Failed to get profile with name: $profileName"))
- StagingProfile(
- id = (currentProfile \ "id").head.text,
- name = (currentProfile \ "name").head.text,
- repositoryTargetId = (currentProfile \ "repositoryTargetId").head.text,
- resourceURI = (currentProfile \ "resourceURI").head.text
- )
+ StagingProfile(
+ id = (currentProfile \ "id").head.text,
+ name = (currentProfile \ "name").head.text,
+ repositoryTargetId = (currentProfile \ "repositoryTargetId").head.text,
+ resourceURI = (currentProfile \ "resourceURI").head.text
+ )
+ } catch {
+ case e: Exception => throw new Exception(s"Failed to get info for profile: $profileName", e)
+ }
}
// https://oss.sonatype.org/nexus-staging-plugin/default/docs/path__staging_profile_repositories_-profileIdKey-.html
@@ -51,7 +55,7 @@ private final class SonatypeHttpApi(sonatypeURI: String, sonatypeCredentials: St
}
// https://oss.sonatype.org/nexus-staging-plugin/default/docs/path__staging_repository_-repositoryIdKey-.html
- private def getStagingRepoById(repoId: StagingRepositoryId): StagingRepository = {
+ def getStagingRepoById(repoId: StagingRepositoryId): StagingRepository = {
log(s"Retrieving staging repo with id: ${repoId.repositoryId}")
val (_, response) = GET(
uri = s"$sonatypeURI/staging/repository/${repoId.repositoryId}",
@@ -68,7 +72,7 @@ private final class SonatypeHttpApi(sonatypeURI: String, sonatypeCredentials: St
log(s"Creating staging repositories for profile: $profileName")
val (responseCode, response) = POST(
uri = profile.resourceURI + "/start",
- body = createRequestBody("Create staging repository [CBT]").getBytes,
+ body = createRequestBody("CBT staging repository").getBytes,
headers = Map(
"Authorization" -> s"Basic $base64Credentials",
"Content-Type" -> "application/xml"
diff --git a/plugins/sonatype-release/src/sonatype/SonatypeLib.scala b/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
index 4666950..317c60f 100644
--- a/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
+++ b/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
@@ -1,12 +1,11 @@
-package cbt.sonatype
+package cbt
+package sonatype
import java.io.File
import java.net.URL
import java.nio.file.Files._
import java.nio.file.Paths
-import cbt.{ ExitCode, Lib }
-
/**
* Sonatype release process is:
* • get your profile info to publish artifacts
@@ -19,9 +18,9 @@ import cbt.{ ExitCode, Lib }
object SonatypeLib {
- val sonatypeServiceURI: String = "https://oss.sonatype.org/service/local"
+ val serviceURI: String = "https://oss.sonatype.org/service/local"
- val sonatypeSnapshotsURI: String = "https://oss.sonatype.org/content/repositories/snapshots"
+ val snapshotsURI: String = "https://oss.sonatype.org/content/repositories/snapshots"
/**
* login:password for Sonatype access.
@@ -29,7 +28,7 @@ object SonatypeLib {
* • environment variables SONATYPE_USERNAME and SONATYPE_PASSWORD
* • ~/.cbt/sonatype-credentials
*/
- def sonatypeCredentials: String = {
+ def credentials: String = {
def fromEnv = for {
username <- Option(System.getenv("SONATYPE_USERNAME"))
password <- Option(System.getenv("SONATYPE_PASSWORD"))
@@ -51,55 +50,45 @@ object SonatypeLib {
}
}
-final class SonatypeLib(
- sonatypeServiceURI: String,
- sonatypeSnapshotsURI: String,
- sonatypeCredentials: String,
- profileName: String
-)( lib: Lib, log: String => Unit ) {
-
- private val sonatypeApi = new SonatypeHttpApi(sonatypeServiceURI, sonatypeCredentials, profileName)(sonatypeLogger)
+final case class SonatypeLib(
+ profileName: String,
+ serviceURI: String = SonatypeLib.serviceURI,
+ snapshotsURI: String = SonatypeLib.snapshotsURI,
+ credentials: String = SonatypeLib.credentials
+)( implicit logger: Logger ){
+ private val lib: Lib = new Lib(logger)
+ private def log: String => Unit = logger.log("sonatype-release",_)
+ val api = new SonatypeHttpApi(serviceURI, credentials, profileName)(log)
/*
* Signed publish steps:
* • create new staging repo
* • create artifacts and sign them
* • publish jars to created repo
*/
- def sonatypePublishSigned(
- sourceFiles: Seq[File],
- artifacts: Seq[File],
- groupId: String,
- artifactId: String,
- version: String,
- isSnapshot: Boolean,
- scalaMajorVersion: String
- ): ExitCode = {
- if(sourceFiles.nonEmpty) {
- System.err.println(lib.blue("Staring publishing to Sonatype."))
+ def publishSigned( artifacts: Seq[File], releaseFolder: String ) = {
+ import api._
+ System.err.println(lib.blue("Publishing to Sonatype"))
- val profile = getStagingProfile()
+ def publish(deployURI: String) = lib.publishSigned(
+ artifacts, new URL(deployURI ++ releaseFolder), Some(credentials)
+ )
- val deployURI = (if (isSnapshot) {
- sonatypeSnapshotsURI
- } else {
- val repoId = sonatypeApi.createStagingRepo(profile)
- s"${sonatypeServiceURI}/staging/deployByRepositoryId/${repoId.repositoryId}"
- }) + s"/${groupId.replace(".", "/")}/${artifactId}_${scalaMajorVersion}/${version}"
-
- lib.publishSigned(
- artifacts = artifacts,
- url = new URL(deployURI),
- credentials = Some(sonatypeCredentials)
- )
- System.err.println(lib.green("Successfully published artifacts to Sonatype."))
- ExitCode.Success
+ if (releaseFolder.endsWith("-SNAPSHOT")){
+ publish(snapshotsURI)
} else {
- System.err.println(lib.red("Sources are empty, won't publish empty jar."))
- ExitCode.Failure
+ val profile = getStagingProfile
+ val repoId = createStagingRepo(profile)
+ publish(
+ serviceURI ++ "/staging/deployByRepositoryId/" ++ repoId.string
+ )
+ finishRelease( getStagingRepoById(repoId), profile )
}
+
+ System.err.println(lib.green("Successfully published to Sonatype!"))
}
+ /*
/**
* Release is:
* • find staging repo related to current profile;
@@ -107,28 +96,24 @@ final class SonatypeLib(
* • wait until this repo is released;
* • drop this repo.
*/
- def sonatypeRelease(
- groupId: String,
- artifactId: String,
- version: String
- ): ExitCode = {
+ private def release: ExitCode = {
val profile = getStagingProfile()
- sonatypeApi.getStagingRepos(profile).toList match {
+ getStagingRepos(profile).toList match {
case Nil =>
System.err.println(lib.red("No staging repositories found, you need to publish artifacts first."))
ExitCode.Failure
case repo :: Nil =>
- sonatypeApi.finishRelease(repo, profile)
- System.err.println(lib.green(s"Successfully released ${groupId}/${artifactId} v:${version}"))
+ finishRelease(repo, profile)
+ log(lib.green(s"Successfully released artifact"))
ExitCode.Success
case repos =>
- val showRepo = { r: StagingRepository => s"${r.repositoryId} in state: ${r.state}" }
- val toRelease = lib.pickOne(lib.blue(s"More than one staging repo found. Select one of them:"), repos)(showRepo)
-
- toRelease map { repo =>
- sonatypeApi.finishRelease(repo, profile)
- System.err.println(lib.green(s"Successfully released ${groupId}/${artifactId} v:${version}"))
+ lib.pickOne(
+ lib.blue(s"More than one staging repo found. Select one of them:"),
+ repos
+ ){ repo => s"${repo.repositoryId} in state: ${repo.state}" }.map{ repo =>
+ finishRelease(repo, profile)
+ log(lib.green(s"Successfully released artifact"))
ExitCode.Success
} getOrElse {
System.err.println(lib.red("Wrong repository number, try again please."))
@@ -136,14 +121,5 @@ final class SonatypeLib(
}
}
}
-
- private def getStagingProfile() =
- try {
- sonatypeApi.getStagingProfile
- } catch {
- case e: Exception => throw new Exception(s"Failed to get info for profile: $profileName", e)
- }
-
- private def sonatypeLogger: String => Unit = lib.logger.log("Sonatype", _)
-
+ */
}
diff --git a/plugins/sonatype-release/src/sonatype/models.scala b/plugins/sonatype-release/src/sonatype/models.scala
index 88ec3b5..fd02774 100644
--- a/plugins/sonatype-release/src/sonatype/models.scala
+++ b/plugins/sonatype-release/src/sonatype/models.scala
@@ -7,7 +7,9 @@ case class StagingProfile(
resourceURI: String
)
-case class StagingRepositoryId(repositoryId: String)
+case class StagingRepositoryId( string: String ){
+ def repositoryId = string // deprecated
+}
object RepositoryState {
val fromString: String => RepositoryState = {