Check Travis status

This commit is contained in:
Alexandre Archambault 2017-04-24 20:46:23 +02:00
parent c59648bd80
commit d27cec6839
4 changed files with 166 additions and 2 deletions

View File

@ -19,6 +19,31 @@ object Release {
}
}
val checkTravisStatus = ReleaseStep { state =>
val currentHash = state.vcs.currentHash
val build = Travis.builds("coursier/coursier", state.log)
.find { build =>
build.job_ids.headOption.exists { id =>
Travis.job(id, state.log).commit.sha == currentHash
}
}
.getOrElse {
sys.error(s"Status for commit $currentHash not found on Travis")
}
state.log.info(s"Found build ${build.id.value} for commit $currentHash, state: ${build.state}")
build.state match {
case "passed" =>
case _ =>
sys.error(s"Build for $currentHash in state ${build.state}")
}
state
}
val previousReleaseVersion = AttributeKey[String]("previousReleaseVersion")
val initialVersion = AttributeKey[String]("initialVersion")
@ -216,6 +241,7 @@ object Release {
val settings = Seq(
releaseProcess := Seq[ReleaseStep](
checkTravisStatus,
savePreviousReleaseVersion,
checkSnapshotDependencies,
inquireVersions,

134
project/Travis.scala Normal file
View File

@ -0,0 +1,134 @@
import java.io.{ByteArrayOutputStream, InputStream}
import java.net.{HttpURLConnection, URL, URLConnection}
import java.nio.charset.StandardCharsets
import argonaut._
import argonaut.Argonaut._
import argonaut.ArgonautShapeless._
import sbt.Logger
object Travis {
final case class BuildId(value: Long) extends AnyVal
object BuildId {
implicit val decode: DecodeJson[BuildId] =
DecodeJson.LongDecodeJson.map(BuildId(_))
}
final case class JobId(value: Long) extends AnyVal
object JobId {
implicit val decode: DecodeJson[JobId] =
DecodeJson.LongDecodeJson.map(JobId(_))
}
final case class CommitId(value: Long) extends AnyVal
object CommitId {
implicit val decode: DecodeJson[CommitId] =
DecodeJson.LongDecodeJson.map(CommitId(_))
}
final case class Build(
id: BuildId,
job_ids: List[JobId],
pull_request: Boolean,
state: String,
commit_id: CommitId
)
final case class Builds(
builds: List[Build]
)
final case class Commit(
id: CommitId,
sha: String,
branch: String
)
final case class JobDetails(
state: String
)
final case class Job(
commit: Commit,
job: JobDetails
)
private def readFully(is: InputStream): Array[Byte] = {
val buffer = new ByteArrayOutputStream
val data = Array.ofDim[Byte](16384)
var nRead = 0
while ({
nRead = is.read(data, 0, data.length)
nRead != -1
})
buffer.write(data, 0, nRead)
buffer.flush()
buffer.toByteArray
}
private def fetch(url: String, log: Logger): String = {
val url0 = new URL(url)
log.info(s"Fetching $url")
val (rawResp, code) = {
var conn: URLConnection = null
var httpConn: HttpURLConnection = null
var is: InputStream = null
try {
conn = url0.openConnection()
httpConn = conn.asInstanceOf[HttpURLConnection]
httpConn.setRequestProperty("Accept", "application/vnd.travis-ci.2+json")
is = conn.getInputStream
(readFully(is), httpConn.getResponseCode)
} finally {
if (is != null)
is.close()
if (httpConn != null)
httpConn.disconnect()
}
}
if (code / 100 != 2)
sys.error(s"Unexpected response code when getting $url: $code")
new String(rawResp, StandardCharsets.UTF_8)
}
def builds(repo: String, log: Logger): List[Build] = {
val url = s"https://api.travis-ci.org/repos/$repo/builds"
val resp = fetch(url, log)
resp.decodeEither[Builds] match {
case Left(err) =>
sys.error(s"Error decoding response from $url: $err")
case Right(builds) =>
log.info(s"Got ${builds.builds.length} builds")
builds.builds
}
}
def job(id: JobId, log: Logger): Job = {
val url = s"https://api.travis-ci.org/jobs/${id.value}"
val resp = fetch(url, log)
resp.decodeEither[Job] match {
case Left(err) =>
sys.error(s"Error decoding response from $url: $err")
case Right(job) =>
job
}
}
}

View File

@ -1 +1 @@
sbt.version=0.13.8
sbt.version=0.13.15

View File

@ -13,7 +13,11 @@ plugins_(
"org.tpolecat" % "tut-plugin" % "0.4.8"
)
libs += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value
libs ++= Seq(
"org.scala-sbt" % "scripted-plugin" % sbtVersion.value,
compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), // for shapeless / auto type class derivations
"com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M5"
)
// important: this line is matched / substituted during releases (via sbt-release)
def coursierVersion = "1.0.0-RC1"