From 7e2593a293ab68b6d8fb928bcc185726e979dbd7 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:22 +0200 Subject: [PATCH 1/8] Rework plugins.sbt --- project/plugins.sbt | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 7f76b208a..aea457064 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,10 +1,18 @@ -addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.8.2") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.15") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.4.0") -addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.8") -addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-RC1") -addSbtPlugin("io.get-coursier" % "sbt-shading" % "1.0.0-RC1") -addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.13") -libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value + +plugins_( + "io.get-coursier" % "sbt-coursier" % "1.0.0-RC1", + "com.typesafe" % "sbt-mima-plugin" % "0.1.13", + "org.xerial.sbt" % "sbt-pack" % "0.8.2", + "com.jsuereth" % "sbt-pgp" % "1.0.0", + "com.typesafe.sbt" % "sbt-proguard" % "0.2.2", + "org.scala-js" % "sbt-scalajs" % "0.6.15", + "org.scoverage" % "sbt-scoverage" % "1.4.0", + "io.get-coursier" % "sbt-shading" % "1.0.0-RC1", + "org.tpolecat" % "tut-plugin" % "0.4.8" +) + +libs += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value + + +def plugins_(modules: ModuleID*) = modules.map(addSbtPlugin) +def libs = libraryDependencies From ad8eb31b682b6b832a42fe990334f020855dfd09 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:22 +0200 Subject: [PATCH 2/8] Avoid now deprecated method --- .../shared/src/test/scala/coursier/test/CentralTests.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 8dceeb69d..f43283819 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -151,7 +151,7 @@ object CentralTests extends TestSuite { ): Future[T] = async { val res = await(resolve(deps, extraRepo = extraRepo)) - assert(res.errors.isEmpty) + assert(res.metadataErrors.isEmpty) assert(res.conflicts.isEmpty) assert(res.isDone) @@ -444,7 +444,7 @@ object CentralTests extends TestSuite { val res = await(resolve(deps)) - assert(res.errors.isEmpty) + assert(res.metadataErrors.isEmpty) assert(res.conflicts.isEmpty) assert(res.isDone) @@ -479,7 +479,7 @@ object CentralTests extends TestSuite { val res = await(resolve(deps)) - assert(res.errors.isEmpty) + assert(res.metadataErrors.isEmpty) assert(res.conflicts.isEmpty) assert(res.isDone) From ade87bc78f1bdd30da876ea3210d727de1383696 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:22 +0200 Subject: [PATCH 3/8] Update script --- scripts/generate-sbt-launcher.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/generate-sbt-launcher.sh b/scripts/generate-sbt-launcher.sh index be0cc7fd1..164171291 100755 --- a/scripts/generate-sbt-launcher.sh +++ b/scripts/generate-sbt-launcher.sh @@ -6,7 +6,9 @@ COURSIER_VERSION=1.0.0-M15-2 "$(dirname "$0")/../coursier" bootstrap \ "io.get-coursier:sbt-launcher_2.12:$COURSIER_VERSION" \ -r sonatype:releases \ + --no-default \ -i launcher \ -I launcher:org.scala-sbt:launcher-interface:1.0.0 \ -o csbt \ - -J -Djline.shutdownhook=false + -J -Djline.shutdownhook=false \ + "$@" From 142aa5ec2082b42421c7d33281313e5a1863bb87 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:23 +0200 Subject: [PATCH 4/8] Update Appveyor badge required by GitHub org change --- README.md | 2 +- doc/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4935066df..8dca0ff7b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A Scala library to fetch dependencies from Maven / Ivy repositories [![Build Status](https://travis-ci.org/coursier/coursier.svg?branch=master)](https://travis-ci.org/coursier/coursier) -[![Build status (Windows)](https://ci.appveyor.com/api/projects/status/trtum5b7washfbj9?svg=true)](https://ci.appveyor.com/project/coursier/coursier) +[![Build status (Windows)](https://ci.appveyor.com/api/projects/status/yy3svc6ukqpykw5s?svg=true)](https://ci.appveyor.com/project/alexarchambault/coursier-a7n6k) [![Join the chat at https://gitter.im/coursier/coursier](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/coursier/coursier?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Maven Central](https://img.shields.io/maven-central/v/io.get-coursier/coursier_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/io.get-coursier/coursier_2.11) [![Scaladoc](http://javadoc-badge.appspot.com/io.get-coursier/coursier_2.11.svg?label=scaladoc)](http://javadoc-badge.appspot.com/io.get-coursier/coursier_2.11) diff --git a/doc/README.md b/doc/README.md index e86d00110..c85b43913 100644 --- a/doc/README.md +++ b/doc/README.md @@ -5,7 +5,7 @@ A Scala library to fetch dependencies from Maven / Ivy repositories [![Build Status](https://travis-ci.org/coursier/coursier.svg?branch=master)](https://travis-ci.org/coursier/coursier) -[![Build status (Windows)](https://ci.appveyor.com/api/projects/status/trtum5b7washfbj9?svg=true)](https://ci.appveyor.com/project/coursier/coursier) +[![Build status (Windows)](https://ci.appveyor.com/api/projects/status/yy3svc6ukqpykw5s?svg=true)](https://ci.appveyor.com/project/alexarchambault/coursier-a7n6k) [![Join the chat at https://gitter.im/coursier/coursier](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/coursier/coursier?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Maven Central](https://img.shields.io/maven-central/v/io.get-coursier/coursier_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/io.get-coursier/coursier_2.11) [![Scaladoc](http://javadoc-badge.appspot.com/io.get-coursier/coursier_2.11.svg?label=scaladoc)](http://javadoc-badge.appspot.com/io.get-coursier/coursier_2.11) From c59648bd80df52f9d9944d4301715610e00ba123 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:23 +0200 Subject: [PATCH 5/8] Use sbt-release --- project/Publish.scala | 2 +- project/Release.scala | 244 +++++++++++++++++++++++++++++++ project/plugins.sbt | 23 +-- project/project/plugins.sbt | 5 +- scripts/generate-sbt-launcher.sh | 4 +- 5 files changed, 265 insertions(+), 13 deletions(-) create mode 100644 project/Release.scala diff --git a/project/Publish.scala b/project/Publish.scala index a18005312..50b8a03e4 100644 --- a/project/Publish.scala +++ b/project/Publish.scala @@ -62,6 +62,6 @@ object Publish { } ) - lazy val released = pomStuff ++ pushToSonatypeStuff + lazy val released = pomStuff ++ pushToSonatypeStuff ++ Release.settings } diff --git a/project/Release.scala b/project/Release.scala new file mode 100644 index 000000000..3a700c131 --- /dev/null +++ b/project/Release.scala @@ -0,0 +1,244 @@ +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.util.regex.Pattern + +import com.typesafe.sbt.pgp.PgpKeys +import sbt._ +import sbt.Keys._ +import sbtrelease.ReleasePlugin.autoImport._ +import sbtrelease.ReleasePlugin.autoImport.ReleaseTransformations._ + +import scala.io._ + +object Release { + + implicit final class StateOps(val state: State) extends AnyVal { + def vcs: sbtrelease.Vcs = + Project.extract(state).get(releaseVcs).getOrElse { + sys.error("VCS not set") + } + } + + val previousReleaseVersion = AttributeKey[String]("previousReleaseVersion") + val initialVersion = AttributeKey[String]("initialVersion") + + val saveInitialVersion = ReleaseStep { state => + val currentVer = Project.extract(state).get(version) + state.put(initialVersion, currentVer) + } + + def versionChanges(state: State): Boolean = { + + val initialVer = state.get(initialVersion).getOrElse { + sys.error(s"${initialVersion.label} key not set") + } + val (_, nextVer) = state.get(ReleaseKeys.versions).getOrElse { + sys.error(s"${ReleaseKeys.versions.label} key not set") + } + + initialVer == nextVer + } + + + val updateVersionPattern = "(?m)^VERSION=.*$".r + def updateVersionInScript(file: File, newVersion: String): Unit = { + val content = Source.fromFile(file)(Codec.UTF8).mkString + + updateVersionPattern.findAllIn(content).toVector match { + case Seq() => sys.error(s"Found no matches in $file") + case Seq(_) => + case _ => sys.error(s"Found too many matches in $file") + } + + val newContent = updateVersionPattern.replaceAllIn(content, "VERSION=" + newVersion) + Files.write(file.toPath, newContent.getBytes(StandardCharsets.UTF_8)) + } + + + val updateScripts = ReleaseStep { state => + + val (releaseVer, _) = state.get(ReleaseKeys.versions).getOrElse { + sys.error(s"${ReleaseKeys.versions.label} key not set") + } + + val scriptsDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) / "scripts" + val scriptFiles = Seq( + scriptsDir / "generate-launcher.sh", + scriptsDir / "generate-sbt-launcher.sh" + ) + + val vcs = state.vcs + + for (f <- scriptFiles) { + updateVersionInScript(f, releaseVer) + vcs.add(f.getAbsolutePath).!!(state.log) + } + + state + } + + val updateLaunchers = ReleaseStep { state => + + val baseDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) + val scriptsDir = baseDir / "scripts" + val scriptFiles = Seq( + (scriptsDir / "generate-launcher.sh") -> (baseDir / "coursier"), + (scriptsDir / "generate-sbt-launcher.sh") -> (baseDir / "csbt") + ) + + val vcs = state.vcs + + for ((f, output) <- scriptFiles) { + sbt.Process(Seq(f.getAbsolutePath, "-f")).!!(state.log) + vcs.add(output.getAbsolutePath).!!(state.log) + } + + state + } + + val savePreviousReleaseVersion = ReleaseStep { state => + + val cmd = Seq(state.vcs.commandName, "tag", "-l") + + val tag = scala.sys.process.Process(cmd) + .!! + .linesIterator + .toVector + .lastOption + .getOrElse { + sys.error(s"Found no tags when running ${cmd.mkString(" ")}") + } + + val ver = + if (tag.startsWith("v")) + tag.stripPrefix("v") + else + sys.error(s"Last tag '$tag' doesn't start with 'v'") + + state.put(previousReleaseVersion, ver) + } + + val updateTutReadme = ReleaseStep { state => + + val previousVer = state.get(previousReleaseVersion).getOrElse { + sys.error(s"${previousReleaseVersion.label} key not set") + } + val (releaseVer, _) = state.get(ReleaseKeys.versions).getOrElse { + sys.error(s"${ReleaseKeys.versions.label} key not set") + } + + val readmeFile = Project.extract(state).get(baseDirectory.in(ThisBuild)) / "doc" / "README.md" + val pattern = Pattern.quote(previousVer).r + + val content = Source.fromFile(readmeFile)(Codec.UTF8).mkString + val newContent = pattern.replaceAllIn(content, releaseVer) + Files.write(readmeFile.toPath, newContent.getBytes(StandardCharsets.UTF_8)) + + state.vcs.add(readmeFile.getAbsolutePath).!!(state.log) + + state + } + + val stageReadme = ReleaseStep { state => + + val baseDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) + val processedReadmeFile = baseDir / "README.md" + + state.vcs.add(processedReadmeFile.getAbsolutePath).!!(state.log) + + state + } + + + val coursierVersionPattern = s"(?m)^${Pattern.quote("def coursierVersion = \"")}[^${'"'}]*${Pattern.quote("\"")}$$".r + + val updatePluginsSbt = ReleaseStep { state => + + val vcs = state.vcs + + val (releaseVer, _) = state.get(ReleaseKeys.versions).getOrElse { + sys.error(s"${ReleaseKeys.versions.label} key not set") + } + + val baseDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) + val pluginsSbtFile = baseDir / "project" / "plugins.sbt" + val projectPluginsSbtFile = baseDir / "project" / "project" / "plugins.sbt" + + val files = Seq( + pluginsSbtFile, + projectPluginsSbtFile + ) + + for (f <- files) { + val content = Source.fromFile(f)(Codec.UTF8).mkString + + coursierVersionPattern.findAllIn(content).toVector match { + case Seq() => sys.error(s"Found no matches in $f") + case Seq(_) => + case _ => sys.error(s"Found too many matches in $f") + } + + val newContent = coursierVersionPattern.replaceAllIn(content, "def coursierVersion = \"" + releaseVer + "\"") + Files.write(f.toPath, newContent.getBytes(StandardCharsets.UTF_8)) + vcs.add(f.getAbsolutePath).!!(state.log) + } + + state + } + + val commitUpdates = ReleaseStep( + action = { state => + + val (releaseVer, _) = state.get(ReleaseKeys.versions).getOrElse { + sys.error(s"${ReleaseKeys.versions.label} key not set") + } + + state.vcs.commit(s"Updates for $releaseVer", sign = true).!(state.log) + + state + }, + check = { state => + + val vcs = state.vcs + + if (vcs.hasModifiedFiles) + sys.error("Aborting release: unstaged modified files") + + if (vcs.hasUntrackedFiles && !Project.extract(state).get(releaseIgnoreUntrackedFiles)) + sys.error( + "Aborting release: untracked files. Remove them or specify 'releaseIgnoreUntrackedFiles := true' in settings" + ) + + state + } + ) + + + val settings = Seq( + releaseProcess := Seq[ReleaseStep]( + savePreviousReleaseVersion, + checkSnapshotDependencies, + inquireVersions, + saveInitialVersion, + runTest, + setReleaseVersion, + commitReleaseVersion, + publishArtifacts, + releaseStepCommand("sonatypeRelease"), + updateScripts, + updateLaunchers, + updateTutReadme, + releaseStepCommand("tut"), + stageReadme, + updatePluginsSbt, + commitUpdates, + tagRelease, + setNextVersion, + commitNextVersion, + ReleaseStep(_.reload), + pushChanges + ), + releasePublishArtifactsAction := PgpKeys.publishSigned.value + ) + +} diff --git a/project/plugins.sbt b/project/plugins.sbt index aea457064..cbb164012 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,18 +1,23 @@ plugins_( - "io.get-coursier" % "sbt-coursier" % "1.0.0-RC1", - "com.typesafe" % "sbt-mima-plugin" % "0.1.13", - "org.xerial.sbt" % "sbt-pack" % "0.8.2", - "com.jsuereth" % "sbt-pgp" % "1.0.0", - "com.typesafe.sbt" % "sbt-proguard" % "0.2.2", - "org.scala-js" % "sbt-scalajs" % "0.6.15", - "org.scoverage" % "sbt-scoverage" % "1.4.0", - "io.get-coursier" % "sbt-shading" % "1.0.0-RC1", - "org.tpolecat" % "tut-plugin" % "0.4.8" + "io.get-coursier" % "sbt-coursier" % coursierVersion, + "com.typesafe" % "sbt-mima-plugin" % "0.1.13", + "org.xerial.sbt" % "sbt-pack" % "0.8.2", + "com.jsuereth" % "sbt-pgp" % "1.0.0", + "com.typesafe.sbt" % "sbt-proguard" % "0.2.2", + "com.github.gseitz" % "sbt-release" % "1.0.4", + "org.scala-js" % "sbt-scalajs" % "0.6.15", + "org.scoverage" % "sbt-scoverage" % "1.4.0", + "io.get-coursier" % "sbt-shading" % coursierVersion, + "org.xerial.sbt" % "sbt-sonatype" % "1.1", + "org.tpolecat" % "tut-plugin" % "0.4.8" ) libs += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value +// important: this line is matched / substituted during releases (via sbt-release) +def coursierVersion = "1.0.0-RC1" + def plugins_(modules: ModuleID*) = modules.map(addSbtPlugin) def libs = libraryDependencies diff --git a/project/project/plugins.sbt b/project/project/plugins.sbt index dfe274c01..f9b32135b 100644 --- a/project/project/plugins.sbt +++ b/project/project/plugins.sbt @@ -1 +1,4 @@ -addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-RC1") +addSbtPlugin("io.get-coursier" % "sbt-coursier" % coursierVersion) + +// important: this line is matched / substituted during releases (via sbt-release) +def coursierVersion = "1.0.0-RC1" diff --git a/scripts/generate-sbt-launcher.sh b/scripts/generate-sbt-launcher.sh index 164171291..364980aa5 100755 --- a/scripts/generate-sbt-launcher.sh +++ b/scripts/generate-sbt-launcher.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -e -COURSIER_VERSION=1.0.0-M15-2 +VERSION=1.0.0-M15-2 "$(dirname "$0")/../coursier" bootstrap \ - "io.get-coursier:sbt-launcher_2.12:$COURSIER_VERSION" \ + "io.get-coursier:sbt-launcher_2.12:$VERSION" \ -r sonatype:releases \ --no-default \ -i launcher \ From d27cec6839015565c73ec017273459fe6040f081 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:23 +0200 Subject: [PATCH 6/8] Check Travis status --- project/Release.scala | 26 ++++++++ project/Travis.scala | 134 +++++++++++++++++++++++++++++++++++++++ project/build.properties | 2 +- project/plugins.sbt | 6 +- 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 project/Travis.scala diff --git a/project/Release.scala b/project/Release.scala index 3a700c131..1d470aec5 100644 --- a/project/Release.scala +++ b/project/Release.scala @@ -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, diff --git a/project/Travis.scala b/project/Travis.scala new file mode 100644 index 000000000..f02386a2b --- /dev/null +++ b/project/Travis.scala @@ -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 + } + } + +} \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index a6e117b61..64317fdae 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.8 +sbt.version=0.13.15 diff --git a/project/plugins.sbt b/project/plugins.sbt index cbb164012..ffa8bf444 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -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" From d800467c3c370e2d99732dda317e31caab7e5f46 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:23 +0200 Subject: [PATCH 7/8] Check Appveyor status --- project/Appveyor.scala | 31 +++++++++++++++++++++++ project/HttpUtil.scala | 57 ++++++++++++++++++++++++++++++++++++++++++ project/Release.scala | 18 +++++++++++++ project/Travis.scala | 56 ++--------------------------------------- 4 files changed, 108 insertions(+), 54 deletions(-) create mode 100644 project/Appveyor.scala create mode 100644 project/HttpUtil.scala diff --git a/project/Appveyor.scala b/project/Appveyor.scala new file mode 100644 index 000000000..f0983e17f --- /dev/null +++ b/project/Appveyor.scala @@ -0,0 +1,31 @@ +import argonaut._ +import argonaut.Argonaut._ +import argonaut.ArgonautShapeless._ + +import sbt.Logger + +object Appveyor { + + final case class Build( + buildId: Long, + branch: String, + commitId: String, + status: String + ) + + def branchLastBuild(repo: String, branch: String, log: Logger): Build = { + + final case class Response(build: Build) + + val url = s"https://ci.appveyor.com/api/projects/$repo/branch/$branch" + val rawResp = HttpUtil.fetch(url, log) + + rawResp.decodeEither[Response] match { + case Left(err) => + sys.error(s"Error decoding response from $url: $err") + case Right(resp) => + resp.build + } + } + +} diff --git a/project/HttpUtil.scala b/project/HttpUtil.scala new file mode 100644 index 000000000..1cc3637bf --- /dev/null +++ b/project/HttpUtil.scala @@ -0,0 +1,57 @@ +import java.io.{ByteArrayOutputStream, InputStream} +import java.net.{HttpURLConnection, URL, URLConnection} +import java.nio.charset.StandardCharsets + +import sbt.Logger + +object HttpUtil { + + 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 + } + + 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) + } + +} diff --git a/project/Release.scala b/project/Release.scala index 1d470aec5..38fd0ef7d 100644 --- a/project/Release.scala +++ b/project/Release.scala @@ -44,6 +44,23 @@ object Release { state } + val checkAppveyorStatus = ReleaseStep { state => + + val currentHash = state.vcs.currentHash + + val build = Appveyor.branchLastBuild("alexarchambault/coursier-a7n6k", "master", state.log) + + state.log.info(s"Found last build ${build.buildId} for branch master, status: ${build.status}") + + if (build.commitId != currentHash) + sys.error(s"Last master Appveyor build corresponds to commit ${build.commitId}, expected $currentHash") + + if (build.status != "success") + sys.error(s"Last master Appveyor build status: ${build.status}") + + state + } + val previousReleaseVersion = AttributeKey[String]("previousReleaseVersion") val initialVersion = AttributeKey[String]("initialVersion") @@ -242,6 +259,7 @@ object Release { val settings = Seq( releaseProcess := Seq[ReleaseStep]( checkTravisStatus, + checkAppveyorStatus, savePreviousReleaseVersion, checkSnapshotDependencies, inquireVersions, diff --git a/project/Travis.scala b/project/Travis.scala index f02386a2b..e6878d2b3 100644 --- a/project/Travis.scala +++ b/project/Travis.scala @@ -1,7 +1,3 @@ -import java.io.{ByteArrayOutputStream, InputStream} -import java.net.{HttpURLConnection, URL, URLConnection} -import java.nio.charset.StandardCharsets - import argonaut._ import argonaut.Argonaut._ import argonaut.ArgonautShapeless._ @@ -56,58 +52,10 @@ object Travis { ) - 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) + val resp = HttpUtil.fetch(url, log) resp.decodeEither[Builds] match { case Left(err) => @@ -121,7 +69,7 @@ object Travis { def job(id: JobId, log: Logger): Job = { val url = s"https://api.travis-ci.org/jobs/${id.value}" - val resp = fetch(url, log) + val resp = HttpUtil.fetch(url, log) resp.decodeEither[Job] match { case Left(err) => From debf9da7a48057a575042dc7aea3ff87ade678c4 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Mon, 24 Apr 2017 20:46:24 +0200 Subject: [PATCH 8/8] Don't run tests during releases now that the CI statuses are checked --- project/Release.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/project/Release.scala b/project/Release.scala index 38fd0ef7d..911ecb3c1 100644 --- a/project/Release.scala +++ b/project/Release.scala @@ -264,7 +264,6 @@ object Release { checkSnapshotDependencies, inquireVersions, saveInitialVersion, - runTest, setReleaseVersion, commitReleaseVersion, publishArtifacts,