Skip to content
Draft
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
7 changes: 0 additions & 7 deletions .devcontainer/devcontainer.json

This file was deleted.

24 changes: 13 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ jobs:
steps:
- uses: actions/checkout@v5
- uses: coursier/cache-action@v6
- uses: VirtusLab/scala-cli-setup@main
- uses: actions/setup-java@v4
with:
jvm: temurin:21
apps: sbt
power: true
java-version: 25
distribution: temurin
- name: Start up emulators
run: docker compose up -d
- run: sbt buildCliBinary test
run: docker compose up -d
- run: ./mill tests.__.test
publish:
runs-on: ubuntu-latest
name: Publish Artifacts
Expand All @@ -29,17 +28,16 @@ jobs:
steps:
- uses: actions/checkout@v5
- uses: coursier/cache-action@v6
- uses: VirtusLab/scala-cli-setup@main
- uses: actions/setup-java@v4
with:
jvm: temurin:21
apps: sbt
java-version: 25
distribution: temurin
- 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:
Expand All @@ -53,4 +51,8 @@ jobs:
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
run: sbt publishSigned sonaRelease
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
run: |
./mill core.jvm.publish
./mill core.native.publish
./mill cli.publish
1 change: 1 addition & 0 deletions .mill-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1.6
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ See output in `example/out`.
##### Jsoniter Json type and codec example
Jsoniter doesn't ship with a type that can represent raw Json values to be used for mapping of `any` / `object` types,
but it provides methods to read / write raw values as bytes (related [issue](https://github.com/plokhotnyuk/jsoniter-scala/issues/1257)).
Given that we can create a custom type with a codec which can look for example like [that](modules/example-jsoniter-json/shared/src/main/scala/json.scala):
Given that we can create a custom type with a codec which can look for example like [that](modules/example-jsoniter-json/src/main/scala/json.scala):
```scala
package example.jsoniter
import com.github.plokhotnyuk.jsoniter_scala.core.*
Expand Down
222 changes: 222 additions & 0 deletions build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package build

import mill.*
import mill.scalalib.*
import mill.scalanativelib.*
import mill.scalanativelib.api.*
import mill.scalalib.publish.*
import mill.util.VcsVersionModule
import mill.api.Task.Simple
import mill.api.TaskCtx
import os.Path

val scalaVer = "3.8.3"

val scalaNativeVer = "0.5.12"

val sttpClient4Ver = "4.0.23"

val zioVer = "2.1.26"

val zioJsonVer = "0.9.1"

val jsoniterVer = "2.38.12"

val munitVer = "1.3.0"

val upickleVer = "4.4.3"

/** Build the Scala Native CLI binary */
def buildCliBinary: T[PathRef] = Task {
val linked = cli.nativeLink()
val dest = Task.dest / "cli"
os.makeDir.all(dest / os.up)
os.copy.over(linked.path, dest)
PathRef(dest)
}

trait Publishable extends PublishModule with VcsVersionModule {
def pomSettings = PomSettings(
description = "Google Cloud client code generator",
organization = "dev.rolang",
url = "https://github.com/rolang/google-rest-api-codegen",
licenses = Seq(License.MIT),
versionControl = VersionControl.github("rolang", "google-rest-api-codegen"),
developers = Seq(
Developer(id = "rolang", name = "Roman Langolf", url = "https://rolang.dev", email = "rolang@pm.me")
)
)
}

// ---------------------------------------------------------------------------
// core: published as gcp-codegen, JVM + Scala Native
// ---------------------------------------------------------------------------

object core extends Module {
// jvm and native share src via SbtModule's parent-dir convention:
// <moduleDir>/jvm/../src/main/scala == <moduleDir>/src/main/scala

trait CoreModule extends ScalaModule with SbtModule with Publishable {
override def moduleDir: Path = super.moduleDir / ".." / ".." / "modules" / "core"

def scalaVersion = scalaVer
override def artifactName = Task { "gcp-codegen" }
override def mvnDeps = Task { Seq(mvn"com.lihaoyi::upickle::$upickleVer") }
}

object jvm extends CoreModule

object native extends CoreModule with ScalaNativeModule {
def scalaNativeVersion = scalaNativeVer
override def nativeMultithreading: T[Option[Boolean]] = Task { Some(false) }
}
}

// ---------------------------------------------------------------------------
// cli: published as gcp-codegen-cli, Scala Native binary
// ---------------------------------------------------------------------------

object cli extends ScalaNativeModule with Publishable with SbtModule {
override def moduleDir: Path = super.moduleDir / ".." / "modules" / "cli"
def scalaVersion = scalaVer
def scalaNativeVersion = scalaNativeVer
override def moduleDeps = Seq(core.native)
override def artifactName = Task { "gcp-codegen-cli" }
override def nativeMultithreading: T[Option[Boolean]] = Task { Some(false) }
override def releaseMode: T[ReleaseMode] = Task { ReleaseMode.ReleaseFast }
}

// ---------------------------------------------------------------------------
// example-jsoniter-json: not published, JVM + Scala Native
// ---------------------------------------------------------------------------

object exampleJsoniterJson extends Module {
trait ExampleModule extends ScalaModule with SbtModule {
override def moduleDir: Path = super.moduleDir / ".." / ".." / "modules" / "example-jsoniter-json"
def scalaVersion = scalaVer
override def mvnDeps = Task { Seq(mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core:$jsoniterVer") }
override def compileMvnDeps = Task {
Seq(mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVer")
}
}

object jvm extends ExampleModule

object native extends ExampleModule with ScalaNativeModule {
def scalaNativeVersion = scalaNativeVer
}
}

// ---------------------------------------------------------------------------
// testLocal: local dev helper, not published
// ---------------------------------------------------------------------------

object testLocal extends ScalaModule {
override def sources = Task.Sources(moduleDir / "src" / "main" / "scala")
def scalaVersion = scalaVer
override def moduleDeps = Seq(exampleJsoniterJson.jvm)
override def mvnDeps = Task {
Seq(
mvn"com.softwaremill.sttp.client4::core:$sttpClient4Ver",
mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core:$jsoniterVer",
mvn"dev.zio::zio-json:$zioJsonVer",
mvn"dev.zio::zio:$zioVer"
)
}
override def compileMvnDeps = Task {
Seq(mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVer")
}
}

// ---------------------------------------------------------------------------
// Test modules: one per (api, version, httpSource, jsonCodec, arrayType) combo
// ---------------------------------------------------------------------------

type TestKey = (String, String, String, String, String)

val testCombos: Seq[TestKey] = for {
(apiName, apiVersion) <- Seq(
"pubsub" -> "v1",
"storage" -> "v1",
"aiplatform" -> "v1",
"iamcredentials" -> "v1",
"redis" -> "v1",
"sheets" -> "v4"
)
httpSource <- Seq("Sttp4")
jsonCodec <- Seq("ZioJson", "Jsoniter")
arrayType <- Seq("ZioChunk", "List")
} yield (apiName, apiVersion, httpSource, jsonCodec, arrayType)

object tests extends Cross[TestModule](testCombos)
trait TestModule extends Cross.Module5[String, String, String, String, String] with ScalaModule {
val apiName = crossValue
val apiVersion = crossValue2
val httpSource = crossValue3
val jsonCodec = crossValue4
val arrayType = crossValue5

def scalaVersion = scalaVer

override def scalacOptions: T[Seq[String]] =
Task { super.scalacOptions() ++ Seq("-Xmax-inlines:64") }

override def sources: T[Seq[PathRef]] = Task { Seq.empty[PathRef] }

override def moduleDeps: Seq[JavaModule] =
if (jsonCodec == "Jsoniter") Seq(exampleJsoniterJson.jvm) else Seq()

override def mvnDeps: T[Seq[Dep]] = Task {
Seq(mvn"com.softwaremill.sttp.client4::core:$sttpClient4Ver") ++
(jsonCodec match {
case "Jsoniter" =>
Seq(mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core:$jsoniterVer")
case "ZioJson" => Seq(mvn"dev.zio::zio-json:$zioJsonVer")
case other => sys.error(s"Unknown jsonCodec: $other")
}) ++
(arrayType match {
case "ZioChunk" => Seq(mvn"dev.zio::zio:$zioVer")
case _ => Seq.empty
})
}

override def compileMvnDeps: T[Seq[Dep]] = Task {
if (jsonCodec == "Jsoniter")
Seq(mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVer")
else Seq.empty
}

override def generatedSources: T[Seq[PathRef]] = Task {
val dest = Task.dest
val basePkg = s"gcp.$apiName.$apiVersion.${httpSource}_${jsonCodec}_${arrayType}".toLowerCase()
val outSrcDir = dest / "scala"
val ws = implicitly[TaskCtx].workspace
val specFile =
ws / "modules" / "test-resources" / "src" / "main" / "resources" / s"${apiName}_${apiVersion}.json"

val cliBin = buildCliBinary()

os.makeDir.all(outSrcDir)
os.proc(
cliBin.path,
s"-specs=$specFile",
s"-out-dir=$outSrcDir",
s"-out-pkg=$basePkg",
s"-http-source=$httpSource",
s"-json-codec=$jsonCodec",
s"-array-type=$arrayType",
s"-jsoniter-json-type=_root_.example.jsoniter.Json"
).call(cwd = ws)
Seq(PathRef(dest))
}

object test extends ScalaTests {
override def mvnDeps: T[Seq[Dep]] = Task {
Seq(
mvn"org.scalameta::munit:$munitVer",
mvn"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVer"
)
}
def testFramework = "munit.Framework"
}
}
Loading
Loading