1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package cbt
package sonatype
import java.io.File
import java.net.URL
import java.nio.file.Files._
import java.nio.file.Paths
/**
* Sonatype release process is:
* • get your profile info to publish artifacts
* • open staging repository to publish artifacts
* • publish signed artifacts and signatures to staging repository
* • close staging repository
* • promote staging repository
* • drop staging repository
*/
object SonatypeLib {
val serviceURI: String = "https://oss.sonatype.org/service/local"
val snapshotsURI: String = "https://oss.sonatype.org/content/repositories/snapshots"
/**
* login:password for Sonatype access.
* Order of credentials lookup:
* • environment variables SONATYPE_USERNAME and SONATYPE_PASSWORD
* • ~/.cbt/sonatype-credentials
*/
def credentials: String = {
def fromEnv = for {
username <- Option(System.getenv("SONATYPE_USERNAME"))
password <- Option(System.getenv("SONATYPE_PASSWORD"))
} yield s"$username:$password"
def fromFile = {
for {
home <- Option(System.getProperty("user.home"))
credsPath = Paths.get(home, ".cbt", "sonatype-credentials")
} yield new String(readAllBytes(credsPath)).trim
}
fromEnv
.orElse(fromFile)
.getOrElse(throw new Exception(
"No Sonatype credentials found! You can provide them via SONATYPE_USERNAME, SONATYPE_PASSWORD env variables, " +
"or in ~/.cbt/sonatype-credentials file as login:password"
))
}
}
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 publishSigned( artifacts: Seq[File], releaseFolder: String ) = {
import api._
System.err.println(lib.blue("Publishing to Sonatype"))
def publish(deployURI: String) = lib.publishSigned(
artifacts, new URL(deployURI ++ releaseFolder), Some(credentials)
)
val urls = if (releaseFolder.endsWith("-SNAPSHOT")){
publish(snapshotsURI)
} else {
val profile = getStagingProfile
val repoId = createStagingRepo(profile)
val urls = publish(
serviceURI ++ "/staging/deployByRepositoryId/" ++ repoId.string
)
finishRelease( getStagingRepoById(repoId), profile )
urls
}
System.err.println(lib.green("Successfully published to Sonatype!"))
urls
}
/*
/**
* Release is:
* • find staging repo related to current profile;
* • close this staging repo;
* • wait until this repo is released;
* • drop this repo.
*/
private def release: ExitCode = {
val profile = getStagingProfile()
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 =>
finishRelease(repo, profile)
log(lib.green(s"Successfully released artifact"))
ExitCode.Success
case repos =>
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."))
ExitCode.Failure
}
}
}
*/
}
|