-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract shared classes to a separate SDK (#300)
## Task Resolves: #41 ## Description This PR is the first step. After manually releasing the SDK (by _manually_ I mean through a CI job triggered through workflow dispatch), tagging it, and updating its version to SNAPSHOT again, we'll need another PR that would remove the built-in classes and replace them with a dependency (which should be quite easy to do, I already tested it out). I think there's no point in automating anything at this point, especially if we want to fix this bug before we release the article (+ I don't expect these files to change too much, so it shouldn't be too painful).
- Loading branch information
Showing
11 changed files
with
1,203 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: Prepare release of SDK | ||
|
||
on: | ||
workflow_dispatch: | ||
|
||
jobs: | ||
publish: | ||
name: Publish package to Maven Central | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out project sources | ||
uses: actions/checkout@v3 | ||
- name: Set up Java | ||
uses: actions/setup-java@v3 | ||
with: | ||
distribution: adopt | ||
java-version: 11 | ||
- name: Publish package | ||
run: | | ||
./gradlew publishPulumiKotlinSdkPublicationToMavenCentralRepository \ | ||
-Psigning.enabled=true \ | ||
-Psigning.key="${{ secrets.GPG_KEY }}" \ | ||
-Psigning.key.password="${{ secrets.GPG_KEY_PASSWORD }}" \ | ||
-Psonatype.username="${{ secrets.SONATYPE_USERNAME }}" \ | ||
-Psonatype.password="${{ secrets.SONATYPE_PASSWORD }}" \ | ||
-Dorg.gradle.daemon=false \ | ||
-q |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import org.jetbrains.dokka.gradle.DokkaTask | ||
|
||
plugins { | ||
kotlin("jvm") | ||
`java-library` | ||
`maven-publish` | ||
id("org.jetbrains.dokka") | ||
signing | ||
} | ||
|
||
group = "org.virtuslab" | ||
version = "0.9.4.0-SNAPSHOT" | ||
base.archivesName.set("pulumi-kotlin-sdk") | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
api("com.pulumi:pulumi:0.9.4") | ||
api("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.2") | ||
} | ||
|
||
tasks.test { | ||
useJUnitPlatform() | ||
} | ||
|
||
task<Jar>("sourcesJar") { | ||
group = "build" | ||
from(sourceSets.main.get().allSource) | ||
archiveClassifier.set("sources") | ||
} | ||
|
||
tasks.withType<DokkaTask> { | ||
moduleName.set("pulumi-kotlin") | ||
} | ||
|
||
task<Jar>("dokkaJavadocJar") { | ||
dependsOn(tasks["dokkaHtml"]) | ||
group = "documentation" | ||
from(tasks["dokkaHtml"]) | ||
archiveClassifier.set("javadoc") | ||
} | ||
|
||
publishing { | ||
repositories { | ||
maven { | ||
name = "MavenCentral" | ||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") | ||
credentials { | ||
username = findProperty("sonatype.username") as String? | ||
password = findProperty("sonatype.password") as String? | ||
} | ||
} | ||
} | ||
publications { | ||
create<MavenPublication>("pulumiKotlinSdk") { | ||
artifact(tasks.named("sourcesJar")) | ||
artifact(tasks.named("dokkaJavadocJar")) | ||
from(components["java"]) | ||
artifactId = "pulumi-kotlin" | ||
} | ||
|
||
publications | ||
.forEach { | ||
if (it is MavenPublication) { | ||
configurePom(it) | ||
if ((findProperty("signing.enabled") as String).toBoolean()) { | ||
val signingKey = findProperty("signing.key") as String? | ||
val signingKeyPassword = findProperty("signing.key.password") as String? | ||
|
||
signing { | ||
sign(it) | ||
useInMemoryPgpKeys(signingKey, signingKeyPassword) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
fun configurePom(mavenPublication: MavenPublication) { | ||
mavenPublication.pom { | ||
name.set("Pulumi Kotlin") | ||
description.set( | ||
"Build cloud applications and infrastructure by combining the safety and reliability of infrastructure " + | ||
"as code with the power of the Kotlin programming language.", | ||
) | ||
url.set("https://github.com/VirtuslabRnD/pulumi-kotlin") | ||
inceptionYear.set("2022") | ||
|
||
issueManagement { | ||
system.set("GitHub") | ||
url.set("https://github.com/VirtuslabRnD/pulumi-kotlin/issues") | ||
} | ||
|
||
licenses { | ||
license { | ||
name.set("The Apache License, Version 2.0") | ||
url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") | ||
} | ||
} | ||
|
||
developers { | ||
developer { | ||
name.set("Dariusz Dzikon") | ||
email.set("[email protected]") | ||
organization.set("VirtusLab") | ||
} | ||
developer { | ||
name.set("Michal Fudala") | ||
email.set("[email protected]") | ||
organization.set("VirtusLab") | ||
} | ||
developer { | ||
name.set("Julia Plewa") | ||
email.set("[email protected]") | ||
organization.set("VirtusLab") | ||
} | ||
} | ||
|
||
scm { | ||
url.set("https://github.com/VirtuslabRnD/pulumi-kotlin/tree/v$version") | ||
connection.set("scm:git:git://github.com/VirtuslabRnD/pulumi-kotlin.git") | ||
developerConnection.set("scm:git:ssh://github.com:VirtuslabRnD/pulumi-kotlin.git") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.pulumi.kotlin | ||
|
||
import com.pulumi.Context | ||
import com.pulumi.core.Output | ||
import kotlinx.coroutines.runBlocking | ||
import com.pulumi.resources.ComponentResource as JavaComponentResource | ||
import com.pulumi.resources.CustomResource as JavaCustomResource | ||
import com.pulumi.resources.ProviderResource as JavaProviderResource | ||
import com.pulumi.resources.Resource as JavaResource | ||
|
||
@DslMarker | ||
annotation class PulumiTagMarker | ||
|
||
@Suppress("RedundantSuspendModifier") | ||
suspend inline fun <T> T.applySuspend(block: T.() -> Unit): T { | ||
block() | ||
return this | ||
} | ||
|
||
interface ConvertibleToJava<T> { | ||
fun toJava(): T | ||
} | ||
|
||
/** | ||
* Parent class for resources within Kotlin SDK - equivalent to [JavaResource]. | ||
* | ||
* Each resource within Kotlin SDK should have corresponding [ResourceMapper], | ||
* in order to properly translate Java resources to Kotlin representation. | ||
* | ||
* This class serves only as parent for all resources and should not be instantiated, | ||
* it cannot be sealed, because generated subclasses will be placed in other packages. | ||
*/ | ||
@Suppress("UnnecessaryAbstractClass") | ||
abstract class KotlinResource private constructor(internal open val javaResource: JavaResource) { | ||
|
||
val pulumiResourceName: String | ||
get() = javaResource.pulumiResourceName() | ||
|
||
val pulumiResourceType: String | ||
get() = javaResource.pulumiResourceType() | ||
|
||
val urn: Output<String> | ||
get() = javaResource.urn() | ||
|
||
val pulumiChildResources: Set<KotlinResource> | ||
get() = javaResource.pulumiChildResources() | ||
.map { | ||
GlobalResourceMapper.tryMap(it)!! | ||
} | ||
.toSet() | ||
|
||
protected constructor( | ||
javaResource: JavaResource, | ||
mapper: ResourceMapper<KotlinResource>, | ||
) : this(javaResource) { | ||
GlobalResourceMapper.registerMapper(mapper) | ||
} | ||
} | ||
|
||
/** | ||
* Parent class for component resources within Kotlin SDK - equivalent to [JavaComponentResource]. | ||
*/ | ||
@Suppress("UnnecessaryAbstractClass") | ||
abstract class KotlinComponentResource private constructor( | ||
override val javaResource: JavaComponentResource, | ||
mapper: ResourceMapper<KotlinResource>, | ||
) : KotlinResource(javaResource, mapper) | ||
|
||
/** | ||
* Parent class for custom resources within Kotlin SDK - equivalent to [JavaCustomResource]. | ||
*/ | ||
@Suppress("UnnecessaryAbstractClass") | ||
abstract class KotlinCustomResource internal constructor( | ||
override val javaResource: JavaCustomResource, | ||
mapper: ResourceMapper<KotlinResource>, | ||
) : KotlinResource(javaResource, mapper) { | ||
val id: Output<String> | ||
get() = javaResource.id() | ||
} | ||
|
||
/** | ||
* Parent class for provider resources within Kotlin SDK - equivalent to [JavaProviderResource]. | ||
*/ | ||
@Suppress("UnnecessaryAbstractClass") | ||
abstract class KotlinProviderResource internal constructor( | ||
override val javaResource: JavaProviderResource, | ||
mapper: ResourceMapper<KotlinResource>, | ||
) : KotlinResource(javaResource, mapper) | ||
|
||
object Pulumi { | ||
|
||
/** | ||
* Run a Pulumi stack callback and wait for result. | ||
* In case of an error terminates the process with [System.exit]. | ||
* | ||
* @param block the stack to run in Pulumi runtime | ||
*/ | ||
fun run(block: suspend (Context) -> Unit) { | ||
com.pulumi.Pulumi.run { | ||
runBlocking { | ||
block(it) | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Append a value wrapped in an [Output] to exported stack outputs. | ||
* <p> | ||
* This method mutates the context internal state. | ||
* @param name name of the [Output] | ||
* @param value the value to be wrapped in [Output] | ||
* @return the current [Context] | ||
*/ | ||
fun Context.export(name: String, value: Any): Context = export(name, Output.of(value)) |
5 changes: 5 additions & 0 deletions
5
sdk/src/main/kotlin/com/pulumi/kotlin/PulumiNullFieldException.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.pulumi.kotlin | ||
|
||
class PulumiNullFieldException(name: String) : RuntimeException( | ||
"Field $name is required but was not set (or was set to null)", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.pulumi.kotlin | ||
|
||
import com.pulumi.core.Output | ||
import java.util.Optional | ||
import com.pulumi.resources.Resource as JavaResource | ||
|
||
/** | ||
* Interface for creation of mappers for particular resource types. | ||
* It assumes that only subtypes of [JavaResource] from Java SDK can be mapped to Kotlin types. | ||
* | ||
* Type [T] is a specific subtype of [KotlinResource] representing provider's resource in Kotlin SDK, | ||
* mapper will produce objects of this type. | ||
*/ | ||
interface ResourceMapper<out T : KotlinResource> { | ||
/** | ||
* Returns `true` if given subtype of [JavaResource] matches the type | ||
* of [KotlinResource]'s backing object (can be mapped to type [T]), `false` otherwise. | ||
*/ | ||
fun supportsMappingOfType(javaResource: JavaResource): Boolean | ||
|
||
/** | ||
* Creates new instance of corresponding [KotlinResource] for given [JavaResource], | ||
* with given [javaResource] as backing object. | ||
*/ | ||
fun map(javaResource: JavaResource): T | ||
} | ||
|
||
/** | ||
* General mapper for mapping Resources backed by java objects ([JavaResource]). | ||
* | ||
* **In order to work properly, a Kotlin resource should be declared first with use of type-safe builder. | ||
* Only then a corresponding mapper will be registered in application's context.** | ||
*/ | ||
internal object GlobalResourceMapper { | ||
private val mappers: MutableList<ResourceMapper<KotlinResource>> = mutableListOf() | ||
|
||
/** | ||
* Looks for corresponding [ResourceMapper] to given [javaResource] and maps it to proper [KotlinResource]. | ||
* Returns null, if given [javaResource] is null. | ||
*/ | ||
internal fun tryMap(javaResource: JavaResource?): KotlinResource? { | ||
if (javaResource == null) return null | ||
|
||
val mapper = requireNotNull(mappers.find { it.supportsMappingOfType(javaResource) }) { | ||
"mapper for a type ${javaResource::class.java} was either not declared or not instantiated" | ||
} | ||
|
||
return mapper.map(javaResource) | ||
} | ||
|
||
/** | ||
* If given [optionalJavaResource] is present, looks for corresponding [ResourceMapper] | ||
* and maps it to proper [KotlinResource]. Otherwise, returns null. | ||
*/ | ||
internal fun tryMap(optionalJavaResource: Optional<JavaResource>?): KotlinResource? { | ||
return if (optionalJavaResource?.isPresent == true) tryMap(optionalJavaResource.get()) else null | ||
} | ||
|
||
/** | ||
* Looks for corresponding [ResourceMapper] to given [outputJavaResource] | ||
* and transforms it to proper [Output] with [KotlinResource]. | ||
* Returned [Output] can be empty if given [outputJavaResource] is empty. | ||
*/ | ||
internal fun tryMap(outputJavaResource: Output<JavaResource>?): Output<KotlinResource?>? { | ||
return outputJavaResource?.applyValue { tryMap(it) } | ||
} | ||
|
||
/** | ||
* Adds given mapper to set of available mappers. | ||
* Returns `true` if mapper was successfully added, `false` if it already existed within the internal collection. | ||
*/ | ||
internal fun registerMapper(mapper: ResourceMapper<KotlinResource>) = mappers.add(mapper) | ||
|
||
/** | ||
* Removes every registered mapper from internal collection. | ||
*/ | ||
internal fun clearMappers() = mappers.clear() | ||
} |
Oops, something went wrong.