-
Notifications
You must be signed in to change notification settings - Fork 77
/
CiReleasePlugin.scala
184 lines (172 loc) · 6.73 KB
/
CiReleasePlugin.scala
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package com.geirsson
import com.typesafe.sbt.GitPlugin
import com.typesafe.sbt.SbtGit.GitKeys
import com.jsuereth.sbtpgp.SbtPgp
import com.jsuereth.sbtpgp.SbtPgp.autoImport._
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.charset.StandardCharsets
import java.util.Base64
import sbt.Def
import sbt.Keys._
import sbt._
import sbt.plugins.JvmPlugin
import sbtdynver.DynVerPlugin
import sbtdynver.DynVerPlugin.autoImport._
import scala.deprecated
import scala.sys.process._
import scala.util.control.NonFatal
import xerial.sbt.Sonatype
import xerial.sbt.Sonatype.autoImport._
object CiReleasePlugin extends AutoPlugin {
override def trigger = allRequirements
override def requires =
JvmPlugin && SbtPgp && DynVerPlugin && GitPlugin && Sonatype
def isSecure: Boolean =
System.getenv("TRAVIS_SECURE_ENV_VARS") == "true" ||
System.getenv("BUILD_REASON") == "IndividualCI" ||
System.getenv("PGP_SECRET") != null
def isTag: Boolean =
Option(System.getenv("TRAVIS_TAG")).exists(_.nonEmpty) ||
Option(System.getenv("CIRCLE_TAG")).exists(_.nonEmpty) ||
Option(System.getenv("CI_COMMIT_TAG")).exists(_.nonEmpty) ||
Option(System.getenv("BUILD_SOURCEBRANCH"))
.orElse(Option(System.getenv("GITHUB_REF")))
.exists(_.startsWith("refs/tags"))
def releaseTag: String =
Option(System.getenv("TRAVIS_TAG"))
.orElse(Option(System.getenv("BUILD_SOURCEBRANCH")))
.orElse(Option(System.getenv("GITHUB_REF")))
.orElse(Option(System.getenv("CIRCLE_TAG")))
.orElse(Option(System.getenv("CI_COMMIT_TAG")))
.getOrElse("<unknown>")
def currentBranch: String =
Option(System.getenv("TRAVIS_BRANCH"))
.orElse(Option(System.getenv("BUILD_SOURCEBRANCH")))
.orElse(Option(System.getenv("GITHUB_REF")))
.orElse(Option(System.getenv("CIRCLE_BRANCH")))
.orElse(Option(System.getenv("CI_COMMIT_BRANCH")))
.getOrElse("<unknown>")
@deprecated("Deprecated, please use isSecure", "1.4.32")
def isTravisSecure: Boolean = isSecure
@deprecated("Deprecated, please use isTag", "1.4.32")
def isTravisTag: Boolean = isTag
@deprecated("Deprecated, please use releaseTag", "1.4.32")
def travisTag: String = releaseTag
@deprecated("Deprecated, please use currentBranch", "1.4.32")
def travisBranch: String = currentBranch
def isAzure: Boolean =
System.getenv("TF_BUILD") == "True"
def isGithub: Boolean =
System.getenv("GITHUB_ACTION") != null
def isCircleCi: Boolean =
System.getenv("CIRCLECI") == "true"
def isGitlab: Boolean =
System.getenv("GITLAB_CI") == "true"
def setupGpg(): Unit = {
val versionLine = List("gpg", "--version").!!.linesIterator.toList.head
println(versionLine)
val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)""".r
val gpgVersion: Long = versionLine.split(" ").last match {
case TaggedVersion(m, _, _) => m.toLong
case _ => 0L
}
// https://dev.gnupg.org/T2313
val importCommand =
if (gpgVersion < 2L) "--import"
else "--batch --import"
val secret = sys.env("PGP_SECRET")
if (isAzure) {
// base64 encoded gpg secrets are too large for Azure variables but
// they fit within the 4k limit when compressed.
Files.write(Paths.get("gpg.zip"), Base64.getDecoder.decode(secret))
s"unzip gpg.zip".!
s"gpg $importCommand gpg.key".!
} else {
(s"echo $secret" #| "base64 --decode" #| s"gpg $importCommand").!
}
}
private def gitHubScmInfo(user: String, repo: String) =
ScmInfo(
url(s"https://github.com/$user/$repo"),
s"scm:git:https://github.com/$user/$repo.git",
Some(s"scm:git:git@github.com:$user/$repo.git")
)
override lazy val buildSettings: Seq[Def.Setting[_]] = List(
dynverSonatypeSnapshots := true,
scmInfo ~= {
case Some(info) => Some(info)
case None =>
import scala.sys.process._
val identifier = """([^\/]+?)"""
val GitHubHttps = s"https://github.com/$identifier/$identifier(?:\\.git)?".r
val GitHubGit = s"git://github.com:$identifier/$identifier(?:\\.git)?".r
val GitHubSsh = s"git@github.com:$identifier/$identifier(?:\\.git)?".r
try {
val remote = List("git", "ls-remote", "--get-url", "origin").!!.trim()
remote match {
case GitHubHttps(user, repo) => Some(gitHubScmInfo(user, repo))
case GitHubGit(user, repo) => Some(gitHubScmInfo(user, repo))
case GitHubSsh(user, repo) => Some(gitHubScmInfo(user, repo))
case _ => None
}
} catch {
case NonFatal(_) => None
}
}
)
override lazy val globalSettings: Seq[Def.Setting[_]] = List(
publishArtifact.in(Test) := false,
publishMavenStyle := true,
commands += Command.command("ci-release") { currentState =>
if (!isSecure) {
println("No access to secret variables, doing nothing")
currentState
} else {
println(
s"Running ci-release.\n" +
s" branch=$currentBranch"
)
setupGpg()
// https://github.com/olafurpg/sbt-ci-release/issues/64
val reloadKeyFiles =
"; set pgpSecretRing := pgpSecretRing.value; set pgpPublicRing := pgpPublicRing.value"
if (!isTag) {
if (isSnapshotVersion(currentState)) {
println(s"No tag push, publishing SNAPSHOT")
reloadKeyFiles ::
sys.env.getOrElse("CI_SNAPSHOT_RELEASE", "+publish") ::
currentState
} else {
// Happens when a tag is pushed right after merge causing the master branch
// job to pick up a non-SNAPSHOT version even if TRAVIS_TAG=false.
println(
"Snapshot releases must have -SNAPSHOT version number, doing nothing"
)
currentState
}
} else {
println("Tag push detected, publishing a stable release")
reloadKeyFiles ::
sys.env.getOrElse("CI_CLEAN", "; clean ; sonatypeBundleClean") ::
sys.env.getOrElse("CI_RELEASE", "+publishSigned") ::
sys.env.getOrElse("CI_SONATYPE_RELEASE", "sonatypeBundleRelease") ::
currentState
}
}
}
)
override lazy val projectSettings: Seq[Def.Setting[_]] = List(
publishConfiguration :=
publishConfiguration.value.withOverwrite(true),
publishLocalConfiguration :=
publishLocalConfiguration.value.withOverwrite(true),
publishTo := sonatypePublishToBundle.value
)
def isSnapshotVersion(state: State): Boolean = {
version.in(ThisBuild).get(Project.extract(state).structure.data) match {
case Some(v) => v.endsWith("-SNAPSHOT")
case None => throw new NoSuchFieldError("version")
}
}
}