From 7acd36d347f107ab4e929910027f461c0dcb0cc2 Mon Sep 17 00:00:00 2001 From: Roman Langolf Date: Sat, 17 May 2025 12:24:28 +0700 Subject: [PATCH 1/2] setup ci, add scalafmt --- .github/workflows/ci.yml | 54 +++++++++++++++++++ .scalafmt.conf | 3 ++ build.sbt | 25 ++++----- .../rolang/gar/ArtifactregistryHandler.scala | 43 ++++++++------- .../protocol/ArtifactregistryHandler.scala | 2 +- .../coursier/src/test/scala/GetVersions.scala | 4 +- .../scala/dev/rolang/sbt/gar/GarPlugin.scala | 4 +- project/plugins.sbt | 2 + 8 files changed, 96 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .scalafmt.conf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5d5f2ff --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI +on: + push: + branches: [master] + tags: [v*] + pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.run_id || github.ref }} + cancel-in-progress: true +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: coursier/cache-action@v6 + - uses: VirtusLab/scala-cli-setup@main + with: + jvm: temurin:21 + apps: sbt + power: true + - run: sbt +Test/compile + publish: + runs-on: ubuntu-latest + name: Publish Artifacts + needs: [test] + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/master') + steps: + - uses: actions/checkout@v2 + - uses: coursier/cache-action@v6 + - uses: VirtusLab/scala-cli-setup@main + with: + jvm: temurin:21 + apps: sbt + - name: Import signing key + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' + env: + PGP_SECRET: ${{ secrets.PGP_SECRET }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + run: echo $PGP_SECRET | base64 -d -i - | gpg --import + + - name: Import signing key and strip passphrase + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE != '' + env: + PGP_SECRET: ${{ secrets.PGP_SECRET }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + run: | + echo "$PGP_SECRET" | base64 -d -i - > /tmp/signing-key.gpg + echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg + (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) + - name: Publish + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + run: sbt +publishSigned +sonatypeCentralRelease \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..9bd3a4a --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,3 @@ +version = "3.8.3" +runner.dialect = scala3 +maxColumn = 120 \ No newline at end of file diff --git a/build.sbt b/build.sbt index 5298338..d586011 100644 --- a/build.sbt +++ b/build.sbt @@ -14,8 +14,11 @@ ThisBuild / developers := List( ) ) ThisBuild / description := "Google Artifact Registry protocol support for coursier / sbt." -ThisBuild / licenses := List("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt")) +ThisBuild / licenses := Seq(License.Apache2) ThisBuild / homepage := Some(url("https://github.com/rolang/gar-handler")) +ThisBuild / version ~= { v => if (v.contains('+')) s"${v.replace('+', '-')}-SNAPSHOT" else v } +ThisBuild / versionScheme := Some("early-semver") +ThisBuild / sonatypeCredentialHost := xerial.sbt.Sonatype.sonatypeCentralHost lazy val scala213 = "2.13.16" lazy val scala212 = "2.12.20" @@ -23,18 +26,8 @@ lazy val scala212 = "2.12.20" ThisBuild / scalaVersion := scala213 lazy val commonSettings = List( - version := "0.1.3", - credentials += Credentials( - "Sonatype Nexus Repository Manager", - "oss.sonatype.org", - sys.env.getOrElse("SONATYPE_USERNAME", ""), - sys.env.getOrElse("SONATYPE_PASSWORD", ""), - ), - usePgpKeyHex("537C76F3EFF1B9BE6FD238B442BD95234C9636F3"), - sonatypeCredentialHost := "oss.sonatype.org", - sonatypeRepository := s"https://${sonatypeCredentialHost.value}/service/local", - publishTo := sonatypePublishToBundle.value, - publishMavenStyle := true, + publishTo := sonatypePublishToBundle.value, + publishMavenStyle := true, ) lazy val root = (project in file(".")) @@ -42,7 +35,7 @@ lazy val root = (project in file(".")) .aggregate(core, coursier, plugin) .settings( noPublishSettings, - crossScalaVersions := Nil + crossScalaVersions := Nil, ) val noPublishSettings = List( @@ -82,7 +75,7 @@ lazy val coursier = project .settings( moduleName := "gar-coursier", scalaVersion := scala213, - crossScalaVersions := Nil, + crossScalaVersions := Seq(scala213), libraryDependencies ++= Seq( "io.get-coursier" %% "coursier" % "2.1.24" % Test ), @@ -97,7 +90,7 @@ lazy val plugin = project .settings( moduleName := "sbt-gar-handler", scalaVersion := scala212, - crossScalaVersions := Nil, + crossScalaVersions := Seq(scala212), sbtPluginPublishLegacyMavenStyle := false, scriptedLaunchOpts := { scriptedLaunchOpts.value ++ diff --git a/modules/core/src/main/scala/dev/rolang/gar/ArtifactregistryHandler.scala b/modules/core/src/main/scala/dev/rolang/gar/ArtifactregistryHandler.scala index 4fb7398..770f6f4 100644 --- a/modules/core/src/main/scala/dev/rolang/gar/ArtifactregistryHandler.scala +++ b/modules/core/src/main/scala/dev/rolang/gar/ArtifactregistryHandler.scala @@ -5,7 +5,7 @@ import com.google.api.client.http.{ HttpHeaders, HttpRequest, HttpRequestFactory, - HttpResponseException, + HttpResponseException } import java.io.{ByteArrayOutputStream, InputStream, OutputStream} @@ -30,7 +30,7 @@ object ArtifactRegistryUrlHandlerFactory { val scopes: java.util.Collection[String] = ImmutableList.of( "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/cloud-platform.read-only", + "https://www.googleapis.com/auth/cloud-platform.read-only" ) GoogleCredentials.getApplicationDefault().createScoped(scopes) @@ -41,10 +41,10 @@ object ArtifactRegistryUrlHandlerFactory { } private def createHttpRequestFactory( - credentials: GoogleCredentials + credentials: GoogleCredentials ): HttpRequestFactory = { val requestInitializer = new HttpCredentialsAdapter(credentials) - val httpTransport = httpTransportFactory.create() + val httpTransport = httpTransportFactory.create() httpTransport.createRequestFactory(requestInitializer) } @@ -78,17 +78,17 @@ object ArtifactRegistryUrlHandlerFactory { final case class MavenModule(project: String, region: String, repository: String, domain: String, name: String) class ArtifactRegistryUrlConnection( - googleHttpRequestFactory: HttpRequestFactory, - url: URL, + googleHttpRequestFactory: HttpRequestFactory, + url: URL )(implicit - logger: Logger + logger: Logger ) extends HttpURLConnection(url) { - private val isMavenMetadata = url.getPath().endsWith("maven-metadata.xml") + private val isMavenMetadata = url.getPath().endsWith("maven-metadata.xml") private val isMavenMetadataSha1 = url.getPath().endsWith("maven-metadata.xml.sha1") private val module = ( url.getPath.split("/").filter(_.nonEmpty), - url.getHost.split("\\.").headOption.map(_.stripSuffix("-maven")), + url.getHost.split("\\.").headOption.map(_.stripSuffix("-maven")) ) match { case (Array(project, repo, domain, subDomain, name, _*), Some(region)) => MavenModule( @@ -96,7 +96,7 @@ class ArtifactRegistryUrlConnection( region = region, repository = repo, domain = s"$domain.$subDomain", - name = s"$name", + name = s"$name" ) case _ => throw new java.net.MalformedURLException(s"Invalid artifact registry maven url $url") } @@ -150,7 +150,7 @@ class ArtifactRegistryUrlConnection( logger.debug(s"Receiving artifact from url: ${genericUrl}.") if (isMavenMetadata || isMavenMetadataSha1) { - val httpRequest = googleHttpRequestFactory.buildGetRequest(genericUrl) + val httpRequest = googleHttpRequestFactory.buildGetRequest(genericUrl) val httpResponse = appendHeadersBeforeConnect(httpRequest).execute() responseCode = httpResponse.getStatusCode() @@ -158,11 +158,14 @@ class ArtifactRegistryUrlConnection( val resLines = Source.fromInputStream(httpResponse.getContent).getLines() - val versions = resLines.collect { - case l if l.contains("\"name\":") => l.replaceAll("\"|,|\\s", "").split("/").lastOption - case l if l.contains("\"createTime\":") => Some(l.replace("\"createTime\":", "").replace("\"", "").trim()) - case _ => None - }.collect { case Some(v) => v }.toList + val versions = resLines + .collect { + case l if l.contains("\"name\":") => l.replaceAll("\"|,|\\s", "").split("/").lastOption + case l if l.contains("\"createTime\":") => Some(l.replace("\"createTime\":", "").replace("\"", "").trim()) + case _ => None + } + .collect { case Some(v) => v } + .toList .grouped(2) .map { case v :: dt :: Nil => Some((v, OffsetDateTime.parse(dt))) @@ -206,7 +209,7 @@ class ArtifactRegistryUrlConnection( new ByteArrayInputStream(metadataXml.getBytes(StandardCharsets.UTF_8)) } } else { - val httpRequest = googleHttpRequestFactory.buildGetRequest(genericUrl) + val httpRequest = googleHttpRequestFactory.buildGetRequest(genericUrl) val httpResponse = appendHeadersBeforeConnect(httpRequest).execute() responseCode = httpResponse.getStatusCode() @@ -239,8 +242,8 @@ class ArtifactRegistryUrlConnection( genericUrl, new ByteArrayContent( connectedWithHeaders.getContentType, - toByteArray, - ), + toByteArray + ) ) appendHeadersBeforeConnect(httpRequest).execute() @@ -260,7 +263,7 @@ class ArtifactRegistryUrlConnection( override def usingProxy(): Boolean = false private def appendHeadersBeforeConnect( - httpRequest: HttpRequest + httpRequest: HttpRequest ): HttpRequest = { connectedWithHeaders.forEach { case (header, headerValues) => httpRequest.getHeaders.set(header, headerValues) diff --git a/modules/coursier/src/main/scala/coursier/cache/protocol/ArtifactregistryHandler.scala b/modules/coursier/src/main/scala/coursier/cache/protocol/ArtifactregistryHandler.scala index 3a4b913..7638ccf 100644 --- a/modules/coursier/src/main/scala/coursier/cache/protocol/ArtifactregistryHandler.scala +++ b/modules/coursier/src/main/scala/coursier/cache/protocol/ArtifactregistryHandler.scala @@ -6,7 +6,7 @@ import dev.rolang.gar.{ArtifactRegistryUrlHandlerFactory, Logger} class ArtifactregistryHandler extends URLStreamHandlerFactory { // TODO find a way to inject a logger private val logger = new Logger { - override def info(msg: String): Unit = System.out.println(msg) + override def info(msg: String): Unit = System.out.println(msg) override def error(msg: String): Unit = System.err.println(msg) override def debug(msg: String): Unit = () } diff --git a/modules/coursier/src/test/scala/GetVersions.scala b/modules/coursier/src/test/scala/GetVersions.scala index e618604..ee5988a 100644 --- a/modules/coursier/src/test/scala/GetVersions.scala +++ b/modules/coursier/src/test/scala/GetVersions.scala @@ -5,7 +5,7 @@ object GetVersions { // example: asia-maven.pkg.dev/my-project/maven com.example my-package_2.13 def main(args: Array[String]): Unit = { val mavenRoot = "artifactregistry://" + args.head - val module = Module(organization = Organization(args(1)), name = ModuleName(args(2))) + val module = Module(organization = Organization(args(1)), name = ModuleName(args(2))) val versions: Versions.Result = Versions .apply() @@ -20,7 +20,7 @@ object GetVersions { case (r: MavenRepository, Right(versions)) => r.root == mavenRoot && versions.available.nonEmpty case _ => false }, - "versions not found", + "versions not found" ) println(s"Test versions: ${versions.results.mkString("\n")}") diff --git a/modules/sbt/src/main/scala/dev/rolang/sbt/gar/GarPlugin.scala b/modules/sbt/src/main/scala/dev/rolang/sbt/gar/GarPlugin.scala index 9d84610..5905751 100644 --- a/modules/sbt/src/main/scala/dev/rolang/sbt/gar/GarPlugin.scala +++ b/modules/sbt/src/main/scala/dev/rolang/sbt/gar/GarPlugin.scala @@ -18,7 +18,7 @@ object GarPlugin extends AutoPlugin { onLoad in Global := (onLoad in Global).value.andThen { state => val sbtLogger = state.log val logger = new dev.rolang.gar.Logger { - override def info(msg: String): Unit = sbtLogger.info(msg) + override def info(msg: String): Unit = sbtLogger.info(msg) override def error(msg: String): Unit = sbtLogger.err(msg) override def debug(msg: String): Unit = sbtLogger.debug(msg) } @@ -37,6 +37,6 @@ object GarPlugin extends AutoPlugin { }, csrConfiguration := csrConfiguration.value.withProtocolHandlerDependencies( Seq("dev.rolang" % "gar-coursier_2.13" % dev.rolang.gar.version.value) - ), + ) ) ++ super.projectSettings } diff --git a/project/plugins.sbt b/project/plugins.sbt index 5c42992..6078ace 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,4 @@ addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.12.2") +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.0") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") From 6a246cd23872c2e1463b30dc83f7d0e7a2a80fa0 Mon Sep 17 00:00:00 2001 From: Roman Langolf Date: Sat, 17 May 2025 12:32:55 +0700 Subject: [PATCH 2/2] update docs --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 023fb0e..560c237 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -[![Sonatype Releases](https://img.shields.io/nexus/r/https/oss.sonatype.org/dev.rolang/gar-coursier_2.13.svg?label=Sonatype%20Release)](https://oss.sonatype.org/content/repositories/releases/dev/rolang/gar-coursier_2.13/) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.rolang/gar-coursier_2.13/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.rolang/gar-coursier_2.13/) # Google Artifact Registry support for sbt and/or coursier @@ -32,7 +31,7 @@ To use with coursier only use the `dev.rolang:gar-coursier_2.13` package. Example usage via the coursier JVM CLI (ensure default google credentials are set up): ```bash -cs launch coursier:2.1.9 dev.rolang:gar-coursier_2.13:0.1.3 -- \ +cs launch coursier:2.1.24 dev.rolang:gar-coursier_2.13:0.1.3 -- \ resolve \ -r '!artifactregistry://LOCATION-maven.pkg.dev/PROJECT/REPOSITORY' -r central \ org:name:ver @@ -52,5 +51,5 @@ sbt '++2.13; coursier/Test/runMain GetVersions asia-maven.pkg.dev/my-project/mav #### Publish local: ```scala -sbt '++2.13; coursier/publishLocal; ++2.12; plugin/publishLocal' +sbt '+publishLocal' ```