Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
version = "3.8.3"
runner.dialect = scala3
maxColumn = 120
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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'
```
25 changes: 9 additions & 16 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,28 @@ 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"

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("."))
.dependsOn(core, coursier, plugin)
.aggregate(core, coursier, plugin)
.settings(
noPublishSettings,
crossScalaVersions := Nil
crossScalaVersions := Nil,
)

val noPublishSettings = List(
Expand Down Expand Up @@ -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
),
Expand All @@ -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 ++
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.google.api.client.http.{
HttpHeaders,
HttpRequest,
HttpRequestFactory,
HttpResponseException,
HttpResponseException
}

import java.io.{ByteArrayOutputStream, InputStream, OutputStream}
Expand All @@ -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)
Expand All @@ -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)
}

Expand Down Expand Up @@ -78,25 +78,25 @@ 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(
project = project,
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")
}
Expand Down Expand Up @@ -150,19 +150,22 @@ 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()
responseMessage = httpResponse.getStatusMessage()

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)))
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -239,8 +242,8 @@ class ArtifactRegistryUrlConnection(
genericUrl,
new ByteArrayContent(
connectedWithHeaders.getContentType,
toByteArray,
),
toByteArray
)
)

appendHeadersBeforeConnect(httpRequest).execute()
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ()
}
Expand Down
4 changes: 2 additions & 2 deletions modules/coursier/src/test/scala/GetVersions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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")}")
Expand Down
4 changes: 2 additions & 2 deletions modules/sbt/src/main/scala/dev/rolang/sbt/gar/GarPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
}
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -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")