Compare commits

..

14 Commits

16 changed files with 227 additions and 99 deletions

View File

@@ -1,17 +0,0 @@
on: [push]
name: Build
jobs:
build-ubuntu:
name: Commit release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v1
with:
java-version: 11
- name: Build
run: ./gradlew build packageUberJarForCurrentOS

View File

@@ -24,7 +24,7 @@ jobs:
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./core/build/distributions
publish_dir: ./core/build/dist/js/productionExecutable
publish_branch: site
- name: Create Release
id: create_release
@@ -44,6 +44,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: "core/build/compose/jars/*.jar"
asset_path: "./core/build/compose/jars/kmppscriptbuilder.core-linux-x64-${{ env.version }}${{ env.additional_version }}.jar"
asset_name: KotlinPublicationScriptsBuilder-linux-x64.jar
asset_content_type: application/java-archive

View File

@@ -0,0 +1,50 @@
package dev.inmo.kmppscriptbuilder.core.export
import dev.inmo.kmppscriptbuilder.core.models.MavenConfig
const val generateCentralSonatypeUploadingPartImports = """import java.nio.charset.StandardCharsets
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse"""
const val generateCentralSonatypeUploadingPart = """// This script work based on https://ossrh-staging-api.central.sonatype.com/swagger-ui/#/default/manual_upload_repository
// and getting available open repos and just uploading them
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
def taskName = "uploadSonatypePublication"
if (rootProject.tasks.names.contains(taskName) == false) {
rootProject.tasks.register(taskName) {
doLast {
def username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
def password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
def bearer = Base64.getEncoder().encodeToString("${"$"}username:${"$"}password".getBytes(StandardCharsets.UTF_8))
def client = HttpClient.newHttpClient()
def request = HttpRequest.newBuilder()
.uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/search/repositories?state=open"))
.GET()
.header("Content-Type", "application/json")
.header("Authorization", "Bearer ${"$"}bearer")
.build()
def response = client.send(request, HttpResponse.BodyHandlers.ofString())
def keys = new ArrayList<String>()
response.body().findAll("\"key\"[\\s]*:[\\s]*\"[^\"]+\"").forEach {
def key = it.find("[^\"]+\"\$").find("[^\"]+")
keys.add(key)
}
keys.forEach {
println("Start uploading ${"$"}it")
def uploadRequest = HttpRequest.newBuilder()
.uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/upload/repository/${"$"}it?publishing_type=user_managed"))
.POST(HttpRequest.BodyPublishers.ofString(""))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer ${"$"}bearer")
.build()
def uploadResponse = client.send(uploadRequest, HttpResponse.BodyHandlers.ofString())
if (uploadResponse.statusCode() != 200) {
throw new IllegalStateException("Faced error of uploading for repo with key ${"$"}it. Response: ${"$"}uploadResponse")
}
}
}
}
}
}"""

View File

@@ -8,18 +8,41 @@ fun GpgSigning.generateMavenConfig() = when (this) {
"""
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)
}
}
// Workaround to make android sign operations depend on signing tasks
project.getTasks().withType(AbstractPublishToMaven.class).configureEach {
def signingTasks = project.getTasks().withType(Sign.class)
mustRunAfter(signingTasks)
}
// Workaround to make test tasks use sign
project.getTasks().withType(Sign.class).configureEach { signTask ->
def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
// These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
// Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
def debugTestTask = tasks.findByName("linkDebugTest${'$'}pubName")
if (debugTestTask != null) {
signTask.mustRunAfter(debugTestTask)
}
// Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
def testTask = tasks.findByName("compileTestKotlin${'$'}pubName")
if (testTask != null) {
signTask.mustRunAfter(testTask)
}
}
}
"""
GpgSigning.Enabled ->
@@ -37,5 +60,28 @@ task signAll {
dependsOn(it)
}
}
// Workaround to make android sign operations depend on signing tasks
project.getTasks().withType(AbstractPublishToMaven.class).configureEach {
def signingTasks = project.getTasks().withType(Sign.class)
mustRunAfter(signingTasks)
}
// Workaround to make test tasks use sign
project.getTasks().withType(Sign.class).configureEach { signTask ->
def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
// These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
// Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
def debugTestTask = tasks.findByName("linkDebugTest${'$'}pubName")
if (debugTestTask != null) {
signTask.mustRunAfter(debugTestTask)
}
// Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
def testTask = tasks.findByName("compileTestKotlin${'$'}pubName")
if (testTask != null) {
signTask.mustRunAfter(testTask)
}
}
"""
}

View File

@@ -1,19 +1,23 @@
package dev.inmo.kmppscriptbuilder.core.export.js_only
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildJsOnlyMavenConfig(licenses: List<License>): String = """
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""}
apply plugin: 'maven-publish'
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""}
task javadocJar(type: Jar) {
classifier = 'javadoc'
archiveClassifier = 'javadoc'
}
task sourcesJar(type: Jar) {
kotlin.sourceSets.all {
from(kotlin)
}
classifier = 'sources'
archiveClassifier = 'sources'
}
publishing {
@@ -57,11 +61,11 @@ publishing {
""" }}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
${gpgSigning.generateMavenConfig()}
""".trimIndent()

View File

@@ -1,18 +1,22 @@
package dev.inmo.kmppscriptbuilder.core.export.jvm_only
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildJvmOnlyMavenConfig(licenses: List<License>): String = """
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""}
apply plugin: 'maven-publish'
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""}
task javadocJar(type: Jar) {
from javadoc
classifier = 'javadoc'
archiveClassifier = 'javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
archiveClassifier = 'sources'
}
publishing {
@@ -54,11 +58,11 @@ publishing {
""" }}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
${gpgSigning.generateMavenConfig()}
""".trimIndent()

View File

@@ -1,13 +1,16 @@
package dev.inmo.kmppscriptbuilder.core.export.mpp
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart
import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildMultiplatformMavenConfig(licenses: List<License>): String = """
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""}
apply plugin: 'maven-publish'
${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
archiveClassifier = 'javadoc'
}
publishing {
@@ -24,28 +27,24 @@ publishing {
url = "$vcsUrl"
}
developers {
${developers.joinToString("\n") { """
developer {
id = "${it.id}"
name = "${it.name}"
email = "${it.eMail}"
}
""" }}
developers {${developers.joinToString("\n") { """
developer {
id = "${it.id}"
name = "${it.name}"
email = "${it.eMail}"
}""" }}
}
licenses {
${licenses.joinToString("\n") { """
license {
name = "${it.title}"
url = "${it.url}"
}
""" }}
licenses {${licenses.joinToString("\n") { """
license {
name = "${it.title}"
url = "${it.url}"
}""" }}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
repositories {
${repositories.joinToString("\n ") { it.build(" ") }}
}
}
${gpgSigning.generateMavenConfig()}

View File

@@ -26,6 +26,7 @@ data class MavenConfig(
val gpgSigning: GpgSigning = GpgSigning.Disabled,
@Deprecated("Replaced with gpgSigning")
val includeGpgSigning: Boolean = false,
val includeCentralSonatypeUploadingScript: Boolean = false,
)
@Serializable
@@ -61,8 +62,7 @@ return """
credentials {
username = project.hasProperty('${usernameProperty}') ? project.property('${usernameProperty}') : System.getenv('${usernameProperty}')
password = project.hasProperty('${passwordProperty}') ? project.property('${passwordProperty}') : System.getenv('${passwordProperty}')
}
"""
}"""
}
companion object {
@@ -86,7 +86,10 @@ return """
name = "$headerName"
value = project.hasProperty('${headerValueProperty}') ? project.property('${headerValueProperty}') : System.getenv('${headerValueProperty}')
}
"""
authentication {
header(HttpHeaderAuthentication)
}"""
}
companion object {
@@ -115,3 +118,4 @@ ${credsType.buildCredsPart()}
}
val SonatypeRepository = MavenPublishingRepository("sonatype", "https://oss.sonatype.org/service/local/staging/deploy/maven2/")
val CentralSonatypeRepository = MavenPublishingRepository("sonatype", "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/")

View File

@@ -1,6 +1,7 @@
package dev.inmo.kmppscriptbuilder.core.ui
import androidx.compose.runtime.*
import dev.inmo.kmppscriptbuilder.core.models.CentralSonatypeRepository
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
import dev.inmo.kmppscriptbuilder.core.models.MavenConfig
import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository
@@ -23,22 +24,31 @@ class MavenInfoView : VerticalView("Project information") {
internal var projectVcsUrlProperty by mutableStateOf("")
internal var gpgSignProperty by mutableStateOf<GpgSigning>(GpgSigning.Disabled)
internal var publishToMavenCentralProperty by mutableStateOf(false)
internal var publishToCentralSonatypeProperty by mutableStateOf(false)
internal var includeCentralSonatypeUploadingScriptProperty by mutableStateOf(false)
internal val developersView = DevelopersView()
internal val repositoriesView = RepositoriesView()
var mavenConfig: MavenConfig
get() = MavenConfig(
projectNameProperty.ifBlank { defaultProjectName },
projectDescriptionProperty.ifBlank { defaultProjectDescription },
projectUrlProperty,
projectVcsUrlProperty,
developersView.developers,
repositoriesView.repositories + if (publishToMavenCentralProperty) {
listOf(SonatypeRepository)
name = projectNameProperty.ifBlank { defaultProjectName },
description = projectDescriptionProperty.ifBlank { defaultProjectDescription },
url = projectUrlProperty,
vcsUrl = projectVcsUrlProperty,
developers = developersView.developers,
repositories = repositoriesView.repositories + if (publishToMavenCentralProperty) {
listOf(
if (publishToCentralSonatypeProperty) {
CentralSonatypeRepository
} else {
SonatypeRepository
}
)
} else {
emptyList()
},
gpgSignProperty
gpgSigning = gpgSignProperty,
includeCentralSonatypeUploadingScript = includeCentralSonatypeUploadingScriptProperty
)
set(value) {
projectNameProperty = value.name
@@ -50,9 +60,11 @@ class MavenInfoView : VerticalView("Project information") {
} else {
value.gpgSigning
}
publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository }
publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository || it == CentralSonatypeRepository }
developersView.developers = value.developers
repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository }
repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository && it != CentralSonatypeRepository }
publishToCentralSonatypeProperty = value.repositories.any { it == CentralSonatypeRepository }
includeCentralSonatypeUploadingScriptProperty = value.includeCentralSonatypeUploadingScript
}
private val gpgSigningDrawer = GpgSigningOptionDrawerWithView(this)
@@ -100,6 +112,20 @@ class MavenInfoView : VerticalView("Project information") {
publishToMavenCentralProperty,
placeSwitchAtTheStart = true
) { publishToMavenCentralProperty = it }
if (publishToMavenCentralProperty) {
SwitchWithLabel(
"Use Central Sonatype instead of OSSRH (OSSRH has been deprecated)",
publishToCentralSonatypeProperty,
placeSwitchAtTheStart = true
) { publishToCentralSonatypeProperty = it }
if (publishToCentralSonatypeProperty) {
SwitchWithLabel(
"Add 'uploadSonatypePublication' root project task (required for Central Sonatype publishing)",
includeCentralSonatypeUploadingScriptProperty,
placeSwitchAtTheStart = true
) { includeCentralSonatypeUploadingScriptProperty = it }
}
}
developersView.build()
repositoriesView.build()
}

View File

@@ -1,11 +1,18 @@
package dev.inmo.kmppscriptbuilder.core.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Divider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.unit.dp
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
@@ -14,17 +21,29 @@ import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
actual object LicensesDrawer : Drawer<LicensesView> {
@Composable
override fun LicensesView.draw() {
if (searchFieldFocused.value) {
Column {
licensesOffersToShow.value.forEach {
Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
CommonText(it.title) {
itemsList.add(it.toLicenseState())
licenseSearchFilter = ""
}
Divider()
val internalFocusState = remember { mutableStateOf(false) }
if (searchFieldFocused.value || internalFocusState.value) {
}
Column(
Modifier
.let {
if (searchFieldFocused.value) {
it.heightIn(max = 128.dp)
} else {
it.height(0.dp)
}
}
.verticalScroll(rememberScrollState())
) {
licensesOffersToShow.value.forEach {
Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
CommonText(it.title) {
itemsList.add(it.toLicenseState())
licenseSearchFilter = ""
internalFocusState.value = false
}
Divider()
}
}
}
}

View File

@@ -12,6 +12,7 @@ import androidx.compose.material.Divider
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -73,7 +74,11 @@ actual fun CommonTextField(
@Composable
actual fun CommonText(text: String, onClick: (() -> Unit)?) {
Text(text, modifier = Modifier.run { onClick ?.let { clickable(onClick = it) } ?: this })
onClick ?.let {
TextButton(it) {
Text(text)
}
} ?: Text(text)
}
@Composable

View File

@@ -4,18 +4,6 @@ kotlin.js.generate.externals=true
kotlin.incremental=true
kotlin.incremental.js=true
kotlin_version=1.7.20
kotlin_coroutines_version=1.6.4
kotlin_serialisation_core_version=1.4.1
ktor_version=2.1.3
micro_utils_version=0.14.2
compose_version=1.2.1
# Dokka
dokka_version=1.7.20
# Project data
group=dev.inmo

View File

@@ -1,15 +1,15 @@
[versions]
kt = "1.7.20"
kt-serialization = "1.4.1"
kt-coroutines = "1.6.4"
kt = "1.9.20"
kt-serialization = "1.6.0"
kt-coroutines = "1.7.3"
jb-compose = "1.2.1"
jb-dokka = "1.7.20"
microutils = "0.14.2"
kjsuikit = "0.4.1"
jb-compose = "1.5.10"
jb-dokka = "1.9.10"
microutils = "0.20.11"
kjsuikit = "0.7.3"
ktor = "2.1.3"
ktor = "2.3.5"
gh-release = "2.4.1"

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip

View File

@@ -13,7 +13,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version"
api libs.kt.serialization
}
}
commonTest {

View File

@@ -1,4 +1,4 @@
project.version = "$version" + System.getenv("additional_version")
project.version = "$version" + (System.getenv("additional_version") == null ? "" : System.getenv("additional_version"))
project.group = "$group"
// apply from: "$publishGradlePath"
@@ -14,7 +14,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version"
api libs.kt.serialization
}
}
commonTest {