Kotlin-multiplatform: ShadowJar gradle plugin creates empty jar - kotlin

I tried to use ShadowJar gradle pluging to pack my ktor app into fat jar. But as result of shadowJar task i get every time almost empty jar. It contains only manifest (main class is properly set).
Gradle configuration (groovy):
import org.gradle.jvm.tasks.Jar
buildscript {
ext.kotlin_version = '1.3.72'
ext.ktor_version = '1.3.2'
ext.serialization_version = '0.20.0'
ext.sl4j_version = '1.6.1'
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
}
}
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.61'
}
apply plugin: 'kotlinx-serialization'
apply plugin: 'application'
apply plugin: 'java'
mainClassName = 'com.example.JvmMainKt'
apply plugin: 'com.github.johnrengelman.shadow'
repositories {
mavenCentral()
jcenter()
}
group 'com.example'
version '0.0.1'
apply plugin: 'maven-publish'
kotlin {
jvm {
}
js {
browser {
}
nodejs {
}
}
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
mingwX64("mingw") {
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib-common')
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
implementation "io.ktor:ktor-client-core:$ktor_version"
}
}
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
jvmMain {
dependencies {
implementation kotlin('stdlib-jdk8')
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
implementation "io.ktor:ktor-serialization:$ktor_version"
implementation "io.ktor:ktor-server-netty:$ktor_version"
implementation "org.slf4j:slf4j-simple:$sl4j_version"
}
}
jvmTest {
dependencies {
implementation kotlin('test')
implementation kotlin('test-junit')
}
}
jsMain {
dependencies {
implementation kotlin('stdlib-js')
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
}
}
jsTest {
dependencies {
implementation kotlin('test-js')
}
}
mingwMain {
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serialization_version"
}
}
mingwTest {
}
}
}
shadowJar {
mainClassName = 'com.example.JvmMainKt'
mergeServiceFiles()
}

marcu's answer is correct but he doesn't explain why that snipped solved his issue, and he's code snippet cannot be directly converted to build.gradle.kts because a cast is needed to see runtimeDependencyFiles from Kotlin. In groovy, his snippet works because groovy supports duck typing while Kotlin doesnt.
I needed this solution in Gradle Kotlin, so I'm sharing it this way.
The com.github.johnrengelman.shadow gradle plugin is designed to work with regular the java gradle plugin, which builds a single jar by default, so it automatically generates a single fat-jar based on that jar classpath.
The Kotlin-Multiplatform gradle plugin works differently, it creates jar files for each jvm target based on a lot of custom settings that is set up using a methodology that is unique to Kotlin-Multiplatform, that's why the default shadowJar task does not work out of the box on Kotlin-Multiplatform.
To solve this problem, we have to create a new ShadowJar task for each jvm target that we need a fat-jar manually, we can do it after we declare the targets (as marcu's example is showing), or during the creation of them. I'm going to show both ways, but I recommend doing during the creation to avoid having to cast objects.
Another thing is that I created function to apply the needed configuration because I have a 8 JVM targets, so this way I don't need to copy-paste the snipped 8 times, I only call the function instead.
During the creation of the target
The explanations are commented on the code:
// Add this imports on top of your build.gradle.kts file
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
// Since you need a main class, I added this default constant
// which you can change as you need:
val defaultMainClassName: String? = null
// Here I declare the function that will register the new ShadowJar task for the target
// If you need another mainClassName, you can pass it as parameter
fun KotlinJvmTarget.registerShadowJar(mainClassName: String? = defaultMainClassName) {
// We get the name from the target here to avoid conflicting
// with the name of the compilation unit
val targetName = name
// Access the main compilation
// We only want to create ShadowJar
// for the main compilation of the target, not the test
compilations.named("main") {
// Access the tasks
tasks {
// Here we register our custom ShadowJar task,
// it's being prefixed by the target name
val shadowJar = register<ShadowJar>("${targetName}ShadowJar") {
// Allows our task to be grouped alongside with other build task
// this is only for organization
group = "build"
// This is important, it adds all output of the build to the fat-jar
from(output)
// This tells ShadowJar to merge all jars in runtime environment
// into the fat-jar for this target
configurations = listOf(runtimeDependencyFiles)
// Here we configure the name of the resulting fat-jar file
// appendix makes sure we append the target name before the version
archiveAppendix.set(targetName)
// classifier is appended after the version,
// it's a common practice to set this classifier to fat-jars
archiveClassifier.set("all")
// Apply the main class name attribute
if (mainClassName != null) {
manifest {
attributes("Main-Class" to mainClassName)
}
}
// This instruction tells the ShadowJar plugin to combine
// ServiceLoader files together, this is needed because
// a lot of Kotlin libs uses service files and
// they would break without this instruction
mergeServiceFiles()
}
// Finally, we get the normal jar task for this target
// and tells kotlin to execute our recently created ShadowJar task
// after the normal jar task completes
getByName("${targetName}Jar") {
finalizedBy(shadowJar)
}
}
}
}
kotlin {
// Here we create a JVM target
jvm("jvm8") {
// We can configure anything we want
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
// If we need a ShadowJar for it,
// all we have to do now is call
// our custom function
// Here's an example of what I'm saying:
// https://stackoverflow.com/a/57951962/804976
registerShadowJar()
}
// Another one just to illustrate the example
jvm("jvm16") {
compilations.all {
kotlinOptions.jvmTarget = "16"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
registerShadowJar()
}
}
With comments removed
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
val defaultMainClassName: String? = null
fun KotlinJvmTarget.registerShadowJar(mainClassName: String? = defaultMainClassName) {
val targetName = name
compilations.named("main") {
tasks {
val shadowJar = register<ShadowJar>("${targetName}ShadowJar") {
group = "build"
from(output)
configurations = listOf(runtimeDependencyFiles)
archiveAppendix.set(targetName)
archiveClassifier.set("all")
if (mainClassName != null) {
manifest {
attributes("Main-Class" to mainClassName)
}
}
mergeServiceFiles()
}
getByName("${targetName}Jar") {
finalizedBy(shadowJar)
}
}
}
}
kotlin {
jvm("jvm8") {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
registerShadowJar()
}
jvm("jvm16") {
compilations.all {
kotlinOptions.jvmTarget = "16"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
registerShadowJar()
}
}
After the creation of the target
Now, I'm going to comment only the changes:
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
kotlin {
jvm("jvm8") {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
// Not registering on creation this time,
// we are going to register the task later
}
jvm("jvm16") {
compilations.all {
kotlinOptions.jvmTarget = "16"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
}
val defaultMainClassName: String? = null
// Instead of having KotlinJvmTarget as receiver,
// we are going to cast the target to it.
// We are also getting the target name from
// the function parameter
fun registerShadowJar(targetName: String, mainClassName: String? = defaultMainClassName) {
// Get the target casting to KotlinJvmTarget in the process
kotlin.targets.named<KotlinJvmTarget>(targetName) {
// Access the main compilation
compilations.named("main") {
tasks {
val shadowJar = register<ShadowJar>("${targetName}ShadowJar") {
group = "build"
from(output)
configurations = listOf(runtimeDependencyFiles)
archiveAppendix.set(targetName)
archiveClassifier.set("all")
if (mainClassName != null) {
manifest {
attributes("Main-Class" to mainClassName)
}
}
mergeServiceFiles()
}
getByName("${targetName}Jar") {
finalizedBy(shadowJar)
}
}
}
}
}
// Now we call the method for each JVM target that we need to create a ShadowJar
registerShadowJar("jvm8")
registerShadowJar("jvm16")
With comments removed
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
kotlin {
jvm("jvm8") {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
jvm("jvm16") {
compilations.all {
kotlinOptions.jvmTarget = "16"
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
}
val defaultMainClassName: String? = null
fun registerShadowJar(targetName: String, mainClassName: String? = defaultMainClassName) {
kotlin.targets.named<KotlinJvmTarget>(targetName) {
compilations.named("main") {
tasks {
val shadowJar = register<ShadowJar>("${targetName}ShadowJar") {
group = "build"
from(output)
configurations = listOf(runtimeDependencyFiles)
archiveAppendix.set(targetName)
archiveClassifier.set("all")
if (mainClassName != null) {
manifest {
attributes("Main-Class" to mainClassName)
}
}
mergeServiceFiles()
}
getByName("${targetName}Jar") {
finalizedBy(shadowJar)
}
}
}
}
}
registerShadowJar("jvm8")
registerShadowJar("jvm16")

I've faced the same issue in the past, the syntax that was working (for groovy gradle) for me was:
shadowJar {
mergeServiceFiles()
manifest {
attributes 'Main-Class': 'com.example.JvmMainKt'
}
}

I finally found solution to my problem.
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
//...
task shadowJar2(type: ShadowJar) {
def target = kotlin.targets.jvm
from target.compilations.main.output
def runtimeClasspath = target.compilations.main.runtimeDependencyFiles
manifest {
attributes 'Main-Class': mainClassName
}
configurations = [runtimeClasspath]
}

Related

ShareStateFlow in Intelji plugin

I have a ToolWindowFactory class like this
class MyToolWindowFactory : ToolWindowFactory {
private val sharedFlow = MutableSharedFlow<String>(replay = 1)
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
CoroutineScope(Dispatchers.IO).launch {
sharedFlow.emit("VALUE")
}
CoroutineScope(Dispatchers.IO).launch {
sharedFlow.collectLatest {
println("$it")
}
}
}
}
I use SharedFlow for variables, but I get this error after run.
Exception in thread "DefaultDispatcher-worker-3" java.lang.NoClassDefFoundError: Could not initialize class kotlinx.coroutines.CoroutineExceptionHandlerImplKt
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:33)
at kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx_coroutines_core(DispatchedTask.kt:95)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:64)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Does ShareStateFlow work in Intelji Plugin?
build.gradle
plugins {
id 'org.jetbrains.intellij' version '1.5.2'
id 'org.jetbrains.kotlin.jvm' version '1.6.10'
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.3.9"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
// See https://github.com/JetBrains/gradle-intellij-plugin/
intellij {
version = '2021.3.3'
}
patchPluginXml {
changeNotes = """
Add change notes here.<br>
<em>most HTML tags may be used</em>"""
}
test {
useJUnitPlatform()
}

Export Kotlin code to jar is recognized as Java code on the consumer project

I'm working on a multi-module repository. One module exports Kotlin library, and the other one consumes the artifact and uses it.
I've noticed that once I'm trying to use named parameters inside the consumer it tells me that I cannot do this in a non-kotlin code (e.g. from Java). When I've tried to decompile the code of the library I've seen that the code I see there is indeed Java code (however this might be related to the fact that IntelliJ decompile everything into Java?)
The entire code can be found in this following link where demo-app is the consumer and rabbit-hole is the producer
Just for complicity, I'll put the build gradle file of both here as well:
Library:
plugins {
id "java"
id "org.jetbrains.kotlin.jvm"
id "org.jetbrains.kotlin.plugin.allopen"
id "jacoco"
id "maven-publish"
id "org.springframework.boot"
id "io.spring.dependency-management"
id "com.diffplug.spotless"
}
jar {
enabled = true
}
bootJar {
enabled = false
}
dependencies {
implementation group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8"
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-amqp'
// Tests
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation group: 'io.mockk', name: 'mockk', version: '1.12.1'
}
build {
finalizedBy spotlessApply
}
test {
useJUnitPlatform()
finalizedBy spotlessApply
finalizedBy jacocoTestReport
}
publishing {
publications {
maven(MavenPublication) {
groupId = 'com.yonatankarp'
artifactId = project.name
version = project.version
from components.java
versionMapping {
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/yonatankarp/rabbit-hole")
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN")
}
}
}
}
allOpen {
annotation("org.springframework.context.annotation.Configuration")
}
Consumer:
plugins {
id "java"
id "org.jetbrains.kotlin.jvm"
id "org.jetbrains.kotlin.plugin.allopen"
id "jacoco"
id "org.springframework.boot"
id "io.spring.dependency-management"
id "com.diffplug.spotless"
}
group = 'com.yonatankarp'
version "${version}"
sourceCompatibility = '11'
jar {
enabled = false
}
bootJar {
enabled = true
}
repositories {
mavenLocal()
mavenCentral()
maven {
name = "Rabbit Hole"
url = uri("https://maven.pkg.github.com/yonatankarp/rabbit-hole")
credentials {
username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") ?: System.getenv('GITHUB_TOKEN')
}
}
}
dependencies {
implementation group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8"
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation "com.yonatankarp:rabbit-hole:+"
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
build {
finalizedBy spotlessApply
}
test {
useJUnitPlatform()
finalizedBy spotlessApply
finalizedBy jacocoTestReport
}
allOpen {
annotation("org.springframework.context.annotation.Configuration")
}
EDIT
For clarity: Both the library and the consumer of it are written in Kotlin

KSP on Kotlin Multiplatform fails on the kspJs with "Collection has more than one element."

I'm experimenting with KSP (Kotlin Symbol Processing) to see what it's capable of and I'm trying to get it working on a Kotlin Multiplatform project.
When I only enable kspJvm, it works perfectly, as soon as I enable kspJs as well, it fails with "Collection has more than one element."
I've recreated the issue in this demo github project:
https://github.com/janvladimirmostert/observable-demo
In my processor, I have the following config:
build.gradle.kts:
val kspVersion: String by project
group = "io.jvaas"
plugins {
kotlin("multiplatform")
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
sourceSets {
val commonMain by getting
val jvmMain by getting {
dependencies {
implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
}
}
}
}
gradle.properties:
kotlinVersion=1.6.0
kspVersion=1.6.0-1.0.1
src/commonMain/kotlin/io/jvaas/observe/Observable.kt
package io.jvaas.observe
annotation class Observable
src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
io.jvaas.observe.ObservableProcessorProvider
src/jvmMain/kotlin/io/jvaas/observe/ObservableProcessor.kt
class ObservableProcessor(
val codeGenerator: CodeGenerator,
val logger: KSPLogger,
) : SymbolProcessor {
...
}
class ObservableProcessorProvider : SymbolProcessorProvider {
override fun create(
environment: SymbolProcessorEnvironment
): SymbolProcessor {
return ObservableProcessor(environment.codeGenerator, environment.logger)
}
}
In my consumer I have the following:
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target.UMD
group = "com.od"
plugins {
application
id("com.google.devtools.ksp") version "1.6.0-1.0.1"
kotlin("plugin.serialization")
kotlin("multiplatform")
id("com.github.johnrengelman.shadow")
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
js(IR) {
browser {
binaries.executable()
webpackTask {
output.libraryTarget = UMD
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
val serializationVersion = "1.3.1"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
implementation("io.jvaas:jvaas-observe")
}
}
val commonTest by getting
val jvmMain by getting {
dependencies {
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
val jsMain by getting
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
dependencies {
add("kspJvm", "io.jvaas:jvaas-observe")
// add("kspJs", "io.jvaas:jvaas-observe") // <--- fails if enabled
//ksp("io.jvaas:jvaas-observe")
}
application {
mainClassName = "com.od.demo.Main"
}
applications/od-server/src/commonMain/kotlin/com/od/demo/Blah.kt
package com.od.demo
import io.jvaas.observe.Observable
#Observable
class Blah {
var test1: String = ""
var test2: Int = 0
var test3: Array<String> = arrayOf()
}
This correctly gets processed when the kspJvm option is enabled and correctly outpus a file at
applications/od-server/build/generated/ksp/jvmMain/kotlin/com/od/demo/BlahO.kt
If I enable it for kspJs, it fails
add("kspJs", "io.jvaas:jvaas-observe")
Execution failed for task ':applications:od-server:compileProductionExecutableKotlinJs'.
> Failed to calculate the value of task ':applications:od-server:compileProductionExecutableKotlinJs' property 'entryModule$kotlin_gradle_plugin'.
> Collection has more than one element.
I've tried the usual gradle build --info / --debug / --scan but it's not clear where I can start looking to resolve this issue.
As mentioned above, I made a demo project to demonstrate the error:
https://github.com/janvladimirmostert/observable-demo
Any ideas on how to resolve that error?
Issue has been fixed in https://github.com/google/ksp/issues/744 but I'm not sure if it has been released yet.

How to share kotlin multiplatform targets between submodules?

After an eternity I managed to setup a kotlin multi-platform and multi-module project. As there is almost no proper guide or documentation, I have just one more issue I couldn't solve.
Can I share kotlin multiplatform targets between the submodules?
Right now every submodule has a build.gradle.kts containing:
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "15"
}
}
js(IR) {
nodejs()
browser {
testTask {
useKarma {
useChromeHeadless()
webpackConfig.cssSupport.enabled = true
}
}
}
}
}
Obviously, I want all modules to compile to the same platforms using the same versions and it would be nice to not copy this snippet for every module.
Not to mention that the test dependencies are identical as well.
sourceSets {
val commonTest by getting {
dependencies {
implementation("io.kotest:kotest-framework-api:$kotestVersion")
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
implementation("io.kotest:kotest-property:$kotestVersion")
}
}
val jvmTest by getting {
dependsOn(commonTest)
dependencies {
implementation("io.kotest:kotest-runner-junit5:$kotestVersion")
}
}
val jsTest by getting {
dependsOn(commonTest)
dependencies {
implementation("io.kotest:kotest-framework-engine:$kotestVersion")
}
}
}

build.gradle.kts following githubs guide: Configuring Gradle for use with GitHub Packages. But it fails finding the "from" function

I have a sample kotlin project that i am trying to get send to github as a package. Below is the contents of my buid.gradle.kts file. I am following this guide: https://docs.github.com/en/packages/guides/configuring-gradle-for-use-with-github-packages#example-using-kotlin-dsl-for-a-single-package-in-the-same-repository
But i can find any help as to why this error happens with the "from" function"
buid.gradle.kts content:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
repositories {
mavenCentral()
}
plugins {
kotlin("jvm") version "1.4.31"
`maven-publish`
}
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/OWNER/REPOSITORY")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
}
publications {
register("gpr") {
from(components["java"]) //This part fails with a Unresolved reference. None of the following
//candidates is applicable because of receiver type mismatch:
}
}
}
group = "me.jeppe"
version = "1.0-SNAPSHOT"
dependencies {
testImplementation(kotlin("test-junit"))
}
tasks.test {
useJUnit()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "1.8"
}
After searching wide and far it appears that i need to write this:
register("gpr", MavenPublication::class)
instead of:
register("gpr")