diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..83c3064 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2022-12-05 + +Initial Release diff --git a/README.md b/README.md index d897862..26c0e58 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,32 @@ -# PBandK Service Generator for Twirp +# PBandK Service Generator and Runtime for Twirp KMM -The project is a [service generator plugin](https://github.com/streem/pbandk#service-code-generation) for [PBandK](https://github.com/streem/pbandk) that generates Kotlin client integration for [Twirp](https://github.com/twitchtv/twirp) services. The generated client code leverages [PBandK](https://github.com/streem/pbandk) for protobuf messages, [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) for [JSON handling of Twirp service errors](https://twitchtv.github.io/twirp/docs/errors.html), and [KTor](https://github.com/ktorio/ktor) for HTTP. All of these choices enable the generated client code to be leveraged in [Kotlin Multiplatform Mobile](https://kotlinlang.org/lp/mobile/) projects, sharing the network integration layer with both iOS and Android native apps. +This project is a [service generator plugin](https://github.com/streem/pbandk#service-code-generation) for [PBandK](https://github.com/streem/pbandk) that generates Kotlin client integration for [Twirp](https://github.com/twitchtv/twirp) services. The generated client code leverages [PBandK](https://github.com/streem/pbandk) for protobuf messages, [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) for [JSON handling of Twirp service errors](https://twitchtv.github.io/twirp/docs/errors.html), and [KTor](https://github.com/ktorio/ktor) for HTTP. All of these choices enable the generated client code to be leveraged in [Kotlin Multiplatform Mobile](https://kotlinlang.org/lp/mobile/) projects, sharing the network integration layer with both iOS and Android native apps. -## Usage +There are two parts to this project - the [generator](./generator) itself, and the supporting [runtime](./runtime) for leveraging the generated service code. -Download the latest release, currently `0.1.0-SNAPSHOT`, and pass it to `protoc` via `pbandk`: +## Generator + +In general, follow [PBandK Usage](https://github.com/streem/pbandk#usage) instructions, but supply the `twirp-kmm-generator` as the `kotlin_service_gen` option as described in [PBandK's Service Code Generation documentation](https://github.com/streem/pbandk#service-code-generation). + +### Usage + +Download the latest release, currently `0.1.0`, and pass it to `protoc` via `pbandk`: ```bash # Download the library to ~ cd ~/ -curl -O https://repo1.maven.org/maven2/com/collectiveidea/twirp/twirp-kmm-generator/0.1.0-SNAPSHOT/twirp-kmm-generator-0.1.0-SNAPSHOT.jar +curl -O https://github.com/collectiveidea/twirp-kmm/releases/download/0.1.0/twirp-kmm-generator-0.1.0.jar ``` + +Pass the jar and generator class name as the `kotlin_service_gen` option to `pbandk_out`: + ```bash cd ~/exampleProject -protoc --pbandk_out=kotlin_service_gen='~/twirp-kmm-generator-0.1.0-SNAPSHOT.jar|com.collectiveidea.twirp.Generator',kotlin_package=com.example.api:src/main/kotlin src/main/proto/example.proto +protoc --pbandk_out=kotlin_service_gen='~/twirp-kmm-generator-0.1.0.jar|com.collectiveidea.twirp.Generator',kotlin_package=com.example.api:src/main/kotlin src/main/proto/example.proto ``` -# Build +### Build To build the library locally, run: @@ -33,3 +42,24 @@ Then, the built version can be used, instead of the latest release, by supplying protoc --pbandk_out=kotlin_service_gen='/Users/darron/Development/twirp-kmm/generator/build/libs/twirp-kmm-generator-0.1.0-SNAPSHOT.jar|com.collectiveidea.twirp.Generator',kotlin_package=com.example.api:shared/src/commonMain/kotlin shared/src/commonMain/proto/example.proto ``` +## Runtime + +The runtime provides an [`installTwirp`](./runtime/src/commonMain/kotlin/com/collectiveidea/twirp/HttpClientTwirpHelper.kt) helper for configuration a KTor HTTPClient for Twirp integration. + +First, add the runtime as a dependency: + +``` +implementation "com.collectiveidea.twirp:twirp-kmm-runtime:0.1.0" +``` + +Then, configure the HTTPClient and pass the client into the generated service constructor: + +```kotlin +val client = HttpClient(engine) { + installTwirp(baseUrl) +} + +val exampleService = ExampleServiceImpl(client) +``` + +Service methods throw a [`ServiceException`](./runtime/src/commonMain/kotlin/com/collectiveidea/twirp/ServiceException.kt) on error. The `ServiceException` contains the parsed error response from the Twirp service JSON body. diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..9927df3 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,44 @@ +# Releasing + +1. Update `version` in `gradle.properties` to the release version. + +2. Update the `CHANGELOG.md`. + +3. Update the `README.md` to reflect the new release version number. + +4. Commit + + ``` + $ git commit -am "Prepare version X.Y.Z" + ``` + +5. Tag + + ``` + $ git tag -am "Version X.Y.Z" X.Y.Z + ``` + +6. Push! + + ``` + $ git push && git push --tags + ``` + +7. Build (generator) + + ``` + $ ./gradlew build + ``` + +8. Create GitHub Release + 1. Visit the [New Releases](https://github.com/collectiveidea/twirp-kmm/releases/new) page. + 2. Supply release version and changelog + 3. Upload `generator/build/libs/twirp-kmm-generator-X.Y.Z.jar` artifact. + +9. Publish (runtime) + + ``` + $ ./gradlew publish + ``` + +10. Visit [Sonatype Nexus](https://s01.oss.sonatype.org) and promote the artifact. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 887f732..a770b41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,3 +12,42 @@ allprojects { google() } } + +fun gradlePropertyOrEnvironmentVariable(name: String) = (project.findProperty(name) ?: System.getenv(name)) as? String + +val signingKeyAsciiArmored = gradlePropertyOrEnvironmentVariable("SIGNING_KEY") +val signingKeyPassword = gradlePropertyOrEnvironmentVariable("SIGNING_PASSWORD") +if (signingKeyAsciiArmored != null) { + subprojects { + plugins.withType { + configure { + useInMemoryPgpKeys(signingKeyAsciiArmored, signingKeyPassword) + sign(extensions.getByType().publications) + } + } + } +} + +val sonatypeUsername = gradlePropertyOrEnvironmentVariable("SONATYPE_USERNAME") +val sonatypePassword = gradlePropertyOrEnvironmentVariable("SONATYPE_PASSWORD") +if (sonatypeUsername != null) { + subprojects { + plugins.withType() { + configure { + repositories { + maven { + name = "oss" + val releasesRepoUrl = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") + val snapshotsRepoUrl = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") + url = if (version.toString().endsWith("-SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl + + credentials { + username = sonatypeUsername + password = sonatypePassword + } + } + } + } + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..876c922 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} diff --git a/buildSrc/src/main/kotlin/MavenPublicationExtensions.kt b/buildSrc/src/main/kotlin/MavenPublicationExtensions.kt new file mode 100644 index 0000000..350a240 --- /dev/null +++ b/buildSrc/src/main/kotlin/MavenPublicationExtensions.kt @@ -0,0 +1,37 @@ +import org.gradle.api.publish.maven.MavenPublication + +fun MavenPublication.configureTwirpKmmPOM(pomDescription: String) { + val pomName = artifactId + + pom { + name.set(pomName) + description.set(pomDescription) + + licenses { + license { + name.set("MIT") + url.set("https://opensource.org/licenses/MIT") + } + } + + url.set("https://github.com/collectiveidea/twirp-kmm") + + issueManagement { + system.set("Github") + url.set("https://github.com/collectiveidea/twirp-kmm/issues") + } + + scm { + connection.set("https://github.com/collectiveidea/twirp-kmm.git") + url.set("https://github.com/collectiveidea/twirp-kmm") + } + + developers { + developer { + id.set("collectiveidea") + name.set("Collective Idea") + url.set("https://github.com/collectiveidea") + } + } + } +} diff --git a/generator/build.gradle.kts b/generator/build.gradle.kts index 775f82f..381a112 100644 --- a/generator/build.gradle.kts +++ b/generator/build.gradle.kts @@ -1,11 +1,15 @@ plugins { id("org.jetbrains.kotlin.jvm") + `maven-publish` + signing } repositories { mavenCentral() } +description = "Twirp service generator PBandK plugin for use in Kotlin Multiplatform Mobile projects." + dependencies { compileOnly("pro.streem.pbandk:pbandk-runtime:0.14.1") compileOnly("pro.streem.pbandk:protoc-gen-pbandk-lib:0.14.1") @@ -28,3 +32,15 @@ tasks.jar { ) } } + +val javadocJar by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") +} + +publishing { + publications.withType { + artifact(javadocJar.get()) + + configureTwirpKmmPOM(project.description!!) + } +} diff --git a/gradle.properties b/gradle.properties index 5ddffb1..44b3839 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -version=0.1.0-SNAPSHOT -group=com.collectiveidea +version=0.1.0 +group=com.collectiveidea.twirp kotlin.code.style=official diff --git a/runtime/build.gradle.kts b/runtime/build.gradle.kts index ee29faf..7f1f7b2 100644 --- a/runtime/build.gradle.kts +++ b/runtime/build.gradle.kts @@ -2,8 +2,12 @@ plugins { kotlin("multiplatform") id("com.android.library") kotlin("plugin.serialization") + `maven-publish` + signing } +description = "Runtime for Twirp service generator PBandK plugin for use in Kotlin Multiplatform Mobile projects." + kotlin { android { publishAllLibraryVariants() @@ -67,3 +71,15 @@ android { } namespace = "com.collectiveidea" } + +val javadocJar by tasks.registering(Jar::class) { + archiveClassifier.set("javadoc") +} + +publishing { + publications.withType { + artifact(javadocJar.get()) + + configureTwirpKmmPOM(project.description!!) + } +}