diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 59514df..0b83ac0 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -4,7 +4,7 @@ plugins { idea `kotlin-dsl` kotlin("jvm") version "1.6.21" - `project-report` + kotlin("plugin.serialization") version "1.6.21" } val gradleJvmTarget = "11" @@ -19,9 +19,12 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable") implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}") - implementation(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:${libs.versions.kotlinx.serialization.get()}")) - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json") + implementation(platform(libs.kotlinx.coroutines.bom)) + implementation(libs.kotlinx.coroutines.core) + + implementation(platform(libs.kotlinx.serialization.bom)) + implementation(libs.kotlinx.serialization.core) + implementation(libs.kotlinx.serialization.json) // implementation("com.charleskorn.kaml:kaml:0.37.0") implementation("com.github.node-gradle:gradle-node-plugin:${libs.versions.gradleNodePlugin.get()}") @@ -32,13 +35,29 @@ dependencies { implementation("net.swiftzer.semver:semver:${libs.versions.semver.get()}") + implementation(platform(libs.okio.bom)) + implementation(libs.okio.core) + + implementation(gradleKotlinDsl()) + + implementation(libs.kotlinx.cli) + + implementation(platform(libs.ktor.bom)) + implementation(libs.ktor.clientAuth) + implementation(libs.ktor.clientContentNegotiation) + implementation(libs.ktor.clientCore) + implementation(libs.ktor.clientEncoding) + implementation(libs.ktor.clientLogging) + implementation(libs.ktor.clientCIO) + implementation(libs.ktor.clientResources) + implementation(libs.ktor.serializationKotlinxJson) + // https://github.com/avast/gradle-docker-compose-plugin // implementation("com.avast.gradle:gradle-docker-compose-plugin:${Versions.gradleDockerComposePlugin}") - implementation(platform("org.http4k:http4k-bom:${libs.versions.http4k.get()}")) - implementation("org.http4k:http4k-core") - implementation("org.http4k:http4k-client-okhttp") - +// implementation(platform("org.http4k:http4k-bom:${libs.versions.http4k.get()}")) +// implementation("org.http4k:http4k-core") +// implementation("org.http4k:http4k-client-okhttp") // https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 // https://youtrack.jetbrains.com/issue/IDEA-262280#focus=Comments-27-5397040.0-0 @@ -63,14 +82,24 @@ tasks.withType().configureEach { kotlinOptions.freeCompilerArgs += listOf( // "-Xcontext-receivers", - "-opt-in=kotlin.RequiresOptIn", - "-opt-in=kotlin.ExperimentalStdlibApi", - "-opt-in=kotlin.time.ExperimentalTime", + "-Xopt-in=kotlin.RequiresOptIn", + "-Xopt-in=kotlin.ExperimentalStdlibApi", + "-Xopt-in=kotlin.time.ExperimentalTime", // "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", + "-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi", ) } + +afterEvaluate { + tasks.withType().configureEach { + kotlinOptions { + apiVersion = gradleKotlinTarget + languageVersion = gradleKotlinTarget + } + } +} + kotlin { jvmToolchain { (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(gradleJvmTarget)) diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/common.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/common.kt index 2ff5871..27da996 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/common.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/common.kt @@ -13,16 +13,10 @@ val jsonMapper = Json { object Versions { - const val kotlinLang = "1.6" - const val jvmTarget = "11" const val node = "14.19.1" - // const val kotlinWrappers = "0.0.1-pre.330-kotlin-1.6.20" const val kotlinWrappers = "1.0.0-pre.336" - const val junit = "5.8.2" - const val kotest = "5.2.3" - const val mockk = "1.12.1" } diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPortalPublishClient.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPortalPublishClient.kt new file mode 100644 index 0000000..5f4264d --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPortalPublishClient.kt @@ -0,0 +1,134 @@ +package dev.adamko.kafkatorio.factoriomod + +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.client.plugins.logging.SIMPLE +import io.ktor.client.request.forms.MultiPartFormDataContent +import io.ktor.client.request.forms.formData +import io.ktor.client.request.forms.submitForm +import io.ktor.client.request.header +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import io.ktor.client.statement.bodyAsText +import io.ktor.http.ContentType +import io.ktor.http.Headers +import io.ktor.http.HttpHeaders +import io.ktor.http.Parameters +import io.ktor.http.append +import io.ktor.http.isSuccess +import io.ktor.serialization.kotlinx.json.json +import java.io.File +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.Json +import org.gradle.api.internal.tasks.userinput.UserInputHandler +import org.gradle.kotlin.dsl.support.useToRun +import org.jetbrains.kotlin.cli.common.toBooleanLenient + + +class FactorioModPortalPublishClient( + private val userInputHandler: UserInputHandler, + private val distributionZip: File, + private val modName: String, + private val modVersion: String, + private val portalApiKey: String, + private val portalUploadEndpoint: String, +) { + + private fun client() = HttpClient(CIO) { + install(Logging) { + logger = Logger.SIMPLE + level = LogLevel.ALL + } + install(ContentNegotiation) { + json(Json { + prettyPrint = false + isLenient = true + }) + } + defaultRequest { + header(HttpHeaders.Authorization, "Bearer $portalApiKey") + port = 443 + } + followRedirects = false + expectSuccess = false + } + + fun uploadMod() = runBlocking { + client().useToRun { + val initUploadResponse = initUpload() + + val confirmation = userInputHandler + .askQuestion("Are you sure you want to publish $modName:$modVersion?", "no") + .toBooleanLenient() ?: false + + if (confirmation) { + upload(initUploadResponse) + } else { + println("aborting upload") + } + } + } + + private suspend fun HttpClient.initUpload(): InitUploadResponse.Success { + + val response = submitForm( + url = portalUploadEndpoint, + formParameters = Parameters.build { + append("mod", modName) + } + ) + +// val response = post(portalUploadEndpoint) { +// contentType(ContentType.MultiPart.FormData) +// setBody(Json.encodeToString(InitUploadRequest.serializer(), InitUploadRequest(modName))) +//// setBody(InitUploadRequest(modName)) +// } + println(response) + val initUploadResponse: InitUploadResponse = + Json.decodeFromString(InitUploadResponse.serializer(), response.bodyAsText()) + println(initUploadResponse) + + require(response.status.isSuccess()) { "init upload request failed" } + + return when (initUploadResponse) { + is Failure -> error(initUploadResponse) + is InitUploadResponse.Success -> initUploadResponse + } + } + + private suspend fun HttpClient.upload(initUploadResponse: InitUploadResponse.Success) { + + val requestForm = formData { + append( + "file", + distributionZip.readBytes(), + Headers.build { + append(HttpHeaders.ContentType, ContentType.Application.Zip) + append(HttpHeaders.ContentDisposition, "filename=${distributionZip.name}") + } + ) + } + + + val response = post(initUploadResponse.uploadUrl) { + setBody(MultiPartFormDataContent(requestForm)) + } + + +// val response = submitFormWithBinaryData(initUploadResponse.uploadUrl, requestForm) { +// header(HttpHeaders.Authorization, "Bearer $portalApiKey") +// } + + val submitUploadResponse = + Json.decodeFromString(SubmitUploadResponse.serializer(), response.bodyAsText()) + + println(response) + println(submitUploadResponse) + require(response.status.isSuccess() && submitUploadResponse is SubmitUploadResponse.Success) { "upload request failed" } + } +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPublishTask.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPublishTask.kt new file mode 100644 index 0000000..96cdc58 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/FactorioModPublishTask.kt @@ -0,0 +1,101 @@ +package dev.adamko.kafkatorio.factoriomod + +import io.ktor.http.URLBuilder +import io.ktor.http.takeFrom +import javax.inject.Inject +import kotlinx.coroutines.runBlocking +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.internal.tasks.userinput.UserInputHandler +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.provider.ProviderFactory +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property +import org.gradle.kotlin.dsl.support.get + + +abstract class FactorioModPublishTask @Inject constructor( + objects: ObjectFactory, + providers: ProviderFactory, +) : DefaultTask() { + + @get:InputFile + abstract val distributionZip: RegularFileProperty + + @get:Input + abstract val modName: Property + + @get:Input + abstract val modVersion: Property + +// @get:Input +// abstract val factorioVersion: Property + + /** Bearer API key */ + @get:Input + val portalApiKey: Property = objects.property().convention( + providers.gradleProperty("FACTORIO_MOD_PORTAL_API_KEY") + ) + + @get:Input + val portalApiUrl: Property = objects.property() + .convention("https://mods.factorio.com/api/v2/") + + @get:Input + val portalUploadEndpoint: Property = objects.property() + .convention("mods/releases/init_upload") + + + init { + group = "factorio" + } + + + @TaskAction + fun deploy() = runBlocking { + + + val userInputHandler = services.get() + + val portalUploadEndpoint = URLBuilder(portalApiUrl.get()) + .takeFrom(portalUploadEndpoint.get()) + .buildString() + + val client = FactorioModPortalPublishClient( + userInputHandler, + distributionZip.get().asFile, + modName.get(), + modVersion.get(), + portalApiKey.get(), + portalUploadEndpoint, + ) + + client.uploadMod() + } + +// private fun validateInfoJson() { +// val modVersion = modVersion.get() +// val factorioVersion = factorioVersion.get() +// +// val distributionZip = distributionZip.get().asFile.toOkioPath() +// +// val zipContents = FileSystem.SYSTEM.openZip(distributionZip) +// +// val infoJson = zipContents.read("info.json".toPath()) { +// generateSequence { readUtf8Line() } +// }.joinToString("\n") +// +// val info: FactorioModInfo = Json.decodeFromString(FactorioModInfo.serializer(), infoJson) +// +// require(info.version == modVersion) { +// "mod version mismatch, ${info.version} vs $modVersion " +// } +// +// require(info.factorioVersion == factorioVersion) { +// "Factorio version mismatch, ${info.factorioVersion} vs $factorioVersion " +// } +// } +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/model.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/model.kt new file mode 100644 index 0000000..3ab3770 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/factoriomod/model.kt @@ -0,0 +1,91 @@ +package dev.adamko.kafkatorio.factoriomod + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonContentPolymorphicSerializer +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.jsonObject + + +//@Serializable +//data class InitUploadRequest( +// @SerialName("mod") val modName: String, +//) + + +@Serializable(with = InitUploadResponse.Serializer::class) +sealed interface InitUploadResponse { + + /** + * @param[uploadUrl] URL the mod zip file should be uploaded to + */ + @Serializable + data class Success( + @SerialName("upload_url") val uploadUrl: String, + ) : InitUploadResponse + + object Serializer : + JsonContentPolymorphicSerializer(InitUploadResponse::class) { + override fun selectDeserializer(element: JsonElement) = when { + "upload_url" in element.jsonObject -> Success.serializer() + else -> Failure.serializer() + } + } +} + + +@Serializable(with = SubmitUploadResponse.Serializer::class) +sealed interface SubmitUploadResponse { + + @Serializable + object Success : SubmitUploadResponse + + object Serializer : JsonContentPolymorphicSerializer( + SubmitUploadResponse::class + ) { + override fun selectDeserializer(element: JsonElement) = when { + "success" in element.jsonObject -> Success.serializer() + else -> Failure.serializer() + } + } +} + + +@Serializable +data class Failure( + val error: String? = null, + val message: String? = null, +) : InitUploadResponse, SubmitUploadResponse { + + private val reason: String? + get() = reasons[error] + + override fun toString() = "Failure(error=$error, message=$message, reason=$reason)" + + companion object { + private val reasons: Map = mapOf( + //@formatter:off + "InvalidApiKey" to "Missing or invalid API key for the current endpoint", + "InvalidRequest" to "Invalid request.", + "InternalError" to "Internal error, please try again later.", + "Forbidden" to "Insufficient permission for current endpoint", + "Unknown" to "Unknown error, please try again later.", + "InvalidModRelease" to "Invalid release data in info.json", + "InvalidModUpload" to "Invalid mod data in zipfile", + "UnknownMod" to "Mod does not exist in mod portal", + //@formatter:on + ) + } +} + + +@Serializable +data class FactorioModInfo( + val name: String, + val version: String, + val title: String, + val description: String, + val author: String, + @SerialName("factorio_version") val factorioVersion: String, + val dependencies: List, +) diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/kotlin-jvm.gradle.kts b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/kotlin-jvm.gradle.kts index 216378c..4cc560d 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/kotlin-jvm.gradle.kts +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/kotlin-jvm.gradle.kts @@ -1,6 +1,5 @@ package dev.adamko.kafkatorio.lang -import dev.adamko.kafkatorio.Versions import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -8,41 +7,45 @@ plugins { kotlin("jvm") } +val projectKotlinTarget = "1.6" +val projectJvmTarget = "11" + + dependencies { - implementation(platform("org.jetbrains.kotlin:kotlin-bom")) +// implementation(platform("org.jetbrains.kotlin:kotlin-bom")) - testImplementation(platform("org.junit:junit-bom:${Versions.junit}")) +// testImplementation(platform("org.junit:junit-bom:${Versions.junit}")) testImplementation("org.junit.jupiter:junit-jupiter") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") { - because("Only needed to run tests in a version of IntelliJ IDEA that bundles older versions") - } +// testRuntimeOnly("org.junit.platform:junit-platform-launcher") { +// because("Only needed to run tests in a version of IntelliJ IDEA that bundles older versions") +// } - testImplementation(platform("io.kotest:kotest-bom:${Versions.kotest}")) +// testImplementation(platform("io.kotest:kotest-bom:${Versions.kotest}")) testImplementation("io.kotest:kotest-runner-junit5") testImplementation("io.kotest:kotest-assertions-core") testImplementation("io.kotest:kotest-property") testImplementation("io.kotest:kotest-assertions-json") - testImplementation("io.mockk:mockk:${Versions.mockk}") - + testImplementation("io.mockk:mockk") } tasks.withType().configureEach { kotlinOptions { - jvmTarget = Versions.jvmTarget - apiVersion = Versions.kotlinLang - languageVersion = Versions.kotlinLang - freeCompilerArgs += listOf( + jvmTarget = projectJvmTarget + apiVersion = projectKotlinTarget + languageVersion = projectKotlinTarget + } + + kotlinOptions.freeCompilerArgs += listOf( // "-Xcontext-receivers", - "-opt-in=kotlin.RequiresOptIn", - "-opt-in=kotlin.ExperimentalStdlibApi", - "-opt-in=kotlin.time.ExperimentalTime", + "-opt-in=kotlin.RequiresOptIn", + "-opt-in=kotlin.ExperimentalStdlibApi", + "-opt-in=kotlin.time.ExperimentalTime", // "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", // "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", - ) - } + ) } tasks.compileTestKotlin { @@ -51,10 +54,10 @@ tasks.compileTestKotlin { kotlin { jvmToolchain { - (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(Versions.jvmTarget)) + (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(projectJvmTarget)) } } -tasks.withType { +tasks.withType().configureEach { useJUnitPlatform() } diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts index 59c1c21..a32586f 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts @@ -52,6 +52,6 @@ val updatePackageJson by tasks.registering(UpdatePackageJson::class) { tasks.assemble { dependsOn(updatePackageJson) } -tasks.withType { +tasks.withType().configureEach { dependsOn(updatePackageJson) } diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/FactorioModPortalDeploy.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/FactorioModPortalDeploy.kt deleted file mode 100644 index 73ca284..0000000 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/FactorioModPortalDeploy.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.adamko.kafkatorio.task - -import org.gradle.api.DefaultTask -import org.http4k.client.OkHttp -import org.http4k.core.Method -import org.http4k.core.Request - -abstract class FactorioModPortalDeploy : DefaultTask() { - - init { - super.doFirst { - - val client = OkHttp() - - val request = Request(Method.GET, "https://factorio.com/login?mods=1") - - println(client(request)) - - - } - } - -} diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt index ea4c13d..0985fb0 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt @@ -22,7 +22,7 @@ object JsonPropertiesUpToDateSpec : ExplainingSpec { else -> { - val packageJsonContent = packageJsonFile.get().asFile.readText() + val packageJsonContent = packageJsonFile2.get().asFile.readText() val packageJson = jsonMapper.parseToJsonElement(packageJsonContent).jsonObject val outdatedProperties = propertiesToCheck.get().mapNotNull { (key, expectedVal) -> diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/TypescriptToLuaTask.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/TypescriptToLuaTask.kt index 7bf6fb2..0624185 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/TypescriptToLuaTask.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/TypescriptToLuaTask.kt @@ -2,6 +2,7 @@ package dev.adamko.kafkatorio.task import com.github.gradle.node.npm.task.NpmTask import javax.inject.Inject +import org.gradle.api.file.ConfigurableFileTree import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileSystemOperations import org.gradle.api.plugins.BasePlugin diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt index 32ebb08..0c55c92 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt @@ -13,6 +13,7 @@ import org.gradle.api.provider.MapProperty import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.support.useToRun @@ -20,14 +21,15 @@ import org.jetbrains.kotlin.util.suffixIfNot @CacheableTask abstract class UpdatePackageJson @Inject constructor( - private val providers: ProviderFactory + private val providers: ProviderFactory, ) : DefaultTask() { @get:Input abstract val propertiesToCheck: MapProperty - @get:OutputFile - abstract val packageJsonFile: RegularFileProperty +// @get:OutputFile + @get:Internal + abstract val packageJsonFile2: RegularFileProperty init { group = NodePlugin.NODE_GROUP @@ -36,26 +38,37 @@ abstract class UpdatePackageJson @Inject constructor( outputs.upToDateWhen(JsonPropertiesUpToDateSpec) - super.doFirst { - propertiesToCheck.disallowChanges() - packageJsonFile.disallowChanges() +// super.doFirst { +// propertiesToCheck.disallowChanges() +// packageJsonFile.disallowChanges() +// } + } + + init { + outputs.upToDateWhen { task -> + require(task is UpdatePackageJson) { "$task is not a UpdatePackageJson task" } + + val currentPackageJson = task.currentPackageJson() + val updatedPackageJson = task.updatedPackageJson(currentPackageJson) + + val status = currentPackageJson == updatedPackageJson + logger.lifecycle("package.json is ${if (status) "up to date" else "not up to date"}") + status } } @TaskAction fun exec() { - val packageJsonFile = packageJsonFile.asFile.get() - val propertiesToCheck = propertiesToCheck.get() + val packageJsonFile = packageJsonFile2.asFile.get() - logger.info("updating package.json ${packageJsonFile.canonicalPath}") - val packageJson = jsonMapper.parseToJsonElement(packageJsonFile.readText()).jsonObject + logger.lifecycle("updating package.json ${packageJsonFile.canonicalPath}") - val newJsonProps = propertiesToCheck.mapValues { (_, newVal) -> JsonPrimitive(newVal) } + val currentPackageJson = currentPackageJson() + val updatedPackageJson = updatedPackageJson(currentPackageJson) - val packageJsonUpdate = JsonObject(packageJson + newJsonProps) val packageJsonContentUpdated = jsonMapper - .encodeToString(packageJsonUpdate) + .encodeToString(updatedPackageJson) .suffixIfNot("\n") logger.debug(packageJsonContentUpdated) @@ -64,4 +77,15 @@ abstract class UpdatePackageJson @Inject constructor( write(packageJsonContentUpdated) } } + + private fun currentPackageJson(): JsonObject { + val packageJsonFile = packageJsonFile2.asFile.get() + return jsonMapper.parseToJsonElement(packageJsonFile.readText()).jsonObject + } + + private fun updatedPackageJson(currentPackageJson: JsonObject): JsonObject { + val propertiesToCheck = propertiesToCheck.get() + val newJsonProps = propertiesToCheck.mapValues { (_, newVal) -> JsonPrimitive(newVal) } + return JsonObject(currentPackageJson + newJsonProps) + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 47bba69..0b1fd4e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,7 @@ kotlinJsWrappers = "0.0.1-pre.334" kotlinx-html = "0.7.5" kotlinx-nodejs = "0.0.7" kotlinx-coroutines = "1.6.1" +kotlinx-cli = "0.3.4" ktor = "2.0.1" @@ -77,9 +78,12 @@ kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotl kotlinx-html = { group = "org.jetbrains.kotlinx", name = "kotlinx-html", version.ref = "kotlinx-html" } kotlinx-nodejs = { group = "org.jetbrains.kotlinx", name = "kotlinx-nodejs", version.ref = "kotlinx-nodejs" } +kotlinx-cli = { group = "org.jetbrains.kotlinx", name = "kotlinx-cli", version.ref = "kotlinx-cli" } kotlin-jsWrappers-bom = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-wrappers-bom", version.ref = "kotlinJsWrappers" } + + ## http4k ## http4k-bom = { group = "org.http4k", name = "http4k-bom", version.ref = "http4k" } http4k-core = { group = "org.http4k", name = "http4k-core" } @@ -88,16 +92,27 @@ http4k-client-okhttp = { group = "org.http4k", name = "http4k-client-okhttp" http4k-client-ws = { group = "org.http4k", name = "http4k-client-websocket" } http4k-server = { group = "org.http4k", name = "http4k-server-undertow" } http4k-cloudnative = { group = "org.http4k", name = "http4k-cloudnative" } -http4k-format-json = { group = "org.http4k", name = "http4k-format-jackson" } -http4k-format-xml = { group = "org.http4k", name = "http4k-format-jackson-xml" } -http4k-format-yaml = { group = "org.http4k", name = "http4k-format-jackson-yaml" } +#http4k-format-jackson-json = { group = "org.http4k", name = "http4k-format-jackson" } +#http4k-format-jackson-xml = { group = "org.http4k", name = "http4k-format-jackson-xml" } +#http4k-format-jackson-yaml = { group = "org.http4k", name = "http4k-format-jackson-yaml" } http4k-format-kotlinx = { group = "org.http4k", name = "http4k-format-kotlinx-serialization" } http4k-graphql = { group = "org.http4k", name = "http4k-graphql" } ## ktor ## -ktor-bom = { group = "io.ktor", name = "ktor-bom", version.ref = "ktor" } +ktor-bom = { group = "io.ktor", name = "ktor-bom", version.ref = "ktor" } +ktor-clientAuth = { group = "io.ktor", name = "ktor-client-auth" } +ktor-clientCIO = { group = "io.ktor", name = "ktor-client-cio" } +ktor-clientContentNegotiation = { group = "io.ktor", name = "ktor-client-content-negotiation" } +ktor-clientCore = { group = "io.ktor", name = "ktor-client-core" } +ktor-clientEncoding = { group = "io.ktor", name = "ktor-client-encoding" } +ktor-clientLogging = { group = "io.ktor", name = "ktor-client-logging" } +ktor-clientResources = { group = "io.ktor", name = "ktor-client-resources" } +ktor-clientWebsockets = { group = "io.ktor", name = "ktor-client-websockets" } +ktor-serializationKotlinxJson = { group = "io.ktor", name = "ktor-serialization-kotlinx-json" } + +ktor-test-clientMock = { group = "io.ktor", name = "ktor-client-mock" } ### jackson ## #jackson-bom = { group = " com.fasterxml.jackson.module", name = ":jackson-module-kotlin", version = "2.13.+" } @@ -129,6 +144,7 @@ skrapeit = { group = "it.skrape", name = "skrapeit", version = "1.2.0" } scrimage-core = { group = "com.sksamuel.scrimage", name = "scrimage-core", version.ref = "scrimage" } +semver = { group = "net.swiftzer.semver", name = "semver", version.ref = "semver" } ## okio ## okio-bom = { group = "com.squareup.okio", name = "okio-bom", version.ref = "okio" } @@ -194,9 +210,9 @@ http4k = [ "http4k-client-ws", "http4k-server", "http4k-cloudnative", - "http4k-format-xml", - "http4k-format-json", - "http4k-format-yaml", +# "http4k-format-jackson-xml", +# "http4k-format-jackson-json", +# "http4k-format-jackson-yaml", "http4k-format-kotlinx", ] diff --git a/modules/events-mod/build.gradle.kts b/modules/events-mod/build.gradle.kts index d48c960..866c6a2 100644 --- a/modules/events-mod/build.gradle.kts +++ b/modules/events-mod/build.gradle.kts @@ -1,3 +1,4 @@ +import dev.adamko.kafkatorio.factoriomod.FactorioModPublishTask import dev.adamko.kafkatorio.gradle.asConsumer import dev.adamko.kafkatorio.gradle.asProvider import dev.adamko.kafkatorio.gradle.dropDirectories @@ -50,7 +51,7 @@ val tsSrcDir: Directory = layout.projectDirectory.dir("src/main/typescript") node { - nodeProjectDir.set(tsSrcDir) + nodeProjectDir.set(layout.projectDirectory) } @@ -115,6 +116,15 @@ tasks.distZip { } +val publishMod by tasks.registering(FactorioModPublishTask::class) { + distributionZip.set(tasks.distZip.flatMap { it.archiveFile }) + + val projectModName = project.extra.get("modName") as String + modName.set(projectModName) + modVersion.set(project.version.toString()) +} + + distributions { main { diff --git a/modules/events-server/build.gradle.kts b/modules/events-server/build.gradle.kts index 6e7d04c..d0bfdee 100644 --- a/modules/events-server/build.gradle.kts +++ b/modules/events-server/build.gradle.kts @@ -15,7 +15,7 @@ description = """ val projectId: String by project.extra -val kafkaStateDir = layout.projectDirectory.dir("kafka-state") +val kafkaStateDir: Directory = layout.projectDirectory.dir("kafka-state") dependencies { implementation(platform(projects.modules.versionsPlatform)) @@ -64,7 +64,7 @@ application { // ) } -tasks.withType { +tasks.withType().configureEach { kotlinOptions.freeCompilerArgs += listOf( "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.FlowPreview", diff --git a/modules/factorio-mod-portal-client/build.gradle.kts b/modules/factorio-mod-portal-client/build.gradle.kts index 3475da0..a4700a0 100644 --- a/modules/factorio-mod-portal-client/build.gradle.kts +++ b/modules/factorio-mod-portal-client/build.gradle.kts @@ -3,32 +3,41 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { dev.adamko.kafkatorio.lang.`kotlin-jvm` kotlin("plugin.serialization") - application + `java-gradle-plugin` } dependencies { implementation(platform(projects.modules.versionsPlatform)) - implementation(projects.modules.eventsServer) +// implementation(gradleKotlinDsl()) implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.cli) implementation(libs.kotlinx.coroutines.core) - implementation(libs.bundles.http4k) - implementation(libs.http4k.format.kotlinx) +// implementation(libs.bundles.http4k) +// implementation(libs.http4k.format.kotlinx) - implementation(libs.skrapeit) +// implementation(libs.skrapeit) + + implementation(libs.okio.core) + + implementation(libs.semver) + + implementation(libs.ktor.clientAuth) + implementation(libs.ktor.clientContentNegotiation) + implementation(libs.ktor.clientCore) + implementation(libs.ktor.clientEncoding) + implementation(libs.ktor.clientLogging) + implementation(libs.ktor.clientCIO) + implementation(libs.ktor.clientResources) + implementation(libs.ktor.serializationKotlinxJson) } -// -//application { -// mainClass.set("dev.adamko.kafkatorio.processor.EventProcessorKt") -//} - -tasks.withType { +tasks.withType().configureEach { kotlinOptions.freeCompilerArgs += listOf( "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.FlowPreview", diff --git a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/ApplicationProperties.kt b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/ApplicationProperties.kt deleted file mode 100644 index be38903..0000000 --- a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/ApplicationProperties.kt +++ /dev/null @@ -1,48 +0,0 @@ -package dev.adamko.kafkatorio - -import dev.adamko.kafkatorio.processor.config.env -import dev.adamko.kafkatorio.processor.config.fromEnvVarPath -import dev.adamko.kafkatorio.processor.config.fromResourcesFile -import java.time.Clock -import org.http4k.cloudnative.env.Environment -import org.http4k.cloudnative.env.EnvironmentKey -import org.http4k.cloudnative.env.Secret -import org.http4k.lens.nonEmptyString -import org.http4k.lens.secret - - -/** - * Load properties, in descending priority order, from - * - * 1. Environment variables - * 2. This app's env file (as defined by the environment variable [Lenses.APPLICATION_PROPERTIES_FILE_PATH]) - * # 3. A resources-dir yaml file - * - */ -internal class ApplicationProperties( - vararg environments: Environment = arrayOf( - Environment.env(), - Environment.fromEnvVarPath(), - Environment.fromResourcesFile(".secret.config.yml") - ) -) { - - private val appProps: Environment = - environments.reduce { acc, environment -> acc.overrides(environment) } - - - fun clock(): Clock = Clock.systemUTC() - - - val factorioModPortalUsername: String - get() = EnvironmentKey - .nonEmptyString() - .required("factorio-mod-portal.username")[appProps] - - - val factorioModPortalPassword: Secret - get() = EnvironmentKey - .secret() - .required("factorio-mod-portal.password")[appProps] - -} diff --git a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalClient.kt b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalClient.kt index 55fb5e2..58b6e30 100644 --- a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalClient.kt +++ b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalClient.kt @@ -1,107 +1,107 @@ package dev.adamko.kafkatorio -import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString -import dev.adamko.kafkatorio.processor.serdes.jsonMapper -import it.skrape.core.htmlDocument -import it.skrape.selects.html5.input -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.jsonObject -import org.http4k.client.OkHttp -import org.http4k.core.HttpHandler -import org.http4k.core.Method -import org.http4k.core.Request -import org.http4k.core.Response -import org.http4k.core.body.form -import org.http4k.core.cookie.Cookie -import org.http4k.core.cookie.cookie -import org.http4k.core.cookie.cookies -import org.http4k.core.then -import org.http4k.filter.ClientFilters - - -/** - * * https://github.com/shanemadden/factorio-mod-portal-publish/blob/master/entrypoint.sh - * * https://github.com/nicolas-lang/factorio-create-release-action/blob/master/entrypoint.py - * * https://github.com/nicolas-lang/factorio-create-release-action/blob/master/factorioModPortal.py - * * https://github.com/justarandomgeek/vscode-factoriomod-debug/blob/master/src/ModPackageProvider.ts#L530 - * - * - */ -internal class FactorioModPortalClient( - private val appProps: ApplicationProperties = ApplicationProperties(), - private val loginFormUrl: String = "https://factorio.com/login?mods=1", - private val loginUrl: String = "https://factorio.com/login", -) { - - private val client: HttpHandler = - ClientFilters.FollowRedirects() - .then(OkHttp()) - - private val csrfCookie: Cookie by lazy { fetchCsrfToken() } - private val sessionCookie: Cookie by lazy { login() } - - - private fun fetchCsrfToken(): Cookie { - - val request = Request(Method.GET, loginFormUrl) - val response: Response = client(request) - - val csrfToken = htmlDocument(response.bodyString()) { - input { - withId = csrfTokenName - withAttribute = "name" to csrfTokenName - findFirst { attribute("value") } - } - } - - println("csrfToken: $csrfToken") - return Cookie(csrfTokenName, csrfToken) - } - - - private fun login(): Cookie { - - val loginRequest = Request(Method.POST, loginUrl) - .header("Referer", loginFormUrl) -// .cookie(csrfCookie) - .form("csrf_token", csrfCookie.value) - .form("username_or_email", appProps.factorioModPortalUsername) - .form("password", appProps.factorioModPortalPassword.use { it }) - .form("next_url", "/profile") - - val loginResponse = client(loginRequest) - - println(loginResponse.bodyString()) - - val sessionCookie = loginResponse.cookies() - .first { it.name == "session" && it.domain == ".factorio.com" } - - println("sessionCookie: $sessionCookie") - - return sessionCookie - } - - fun getModInfo(modName: String): JsonObject { - val response = client( - Request(Method.GET, "https://mods.factorio.com/api/mods/${modName}/full") - .cookie(csrfCookie) - .cookie(sessionCookie) - ) - return jsonMapper.parseToJsonElement(response.bodyString()).jsonObject - } - - fun fetchModUploadToken(modName: String): String { - val response = client( - Request(Method.GET, "https://mods.factorio.com/mod/${modName}/edit") - .cookie(csrfCookie) - .cookie(sessionCookie) - ) - - return response.bodyString() - } - - companion object { - private const val csrfTokenName = "csrf_token" - } - -} +//import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString +//import dev.adamko.kafkatorio.processor.serdes.jsonMapper +//import it.skrape.core.htmlDocument +//import it.skrape.selects.html5.input +//import kotlinx.serialization.json.JsonObject +//import kotlinx.serialization.json.jsonObject +//import org.http4k.client.OkHttp +//import org.http4k.core.HttpHandler +//import org.http4k.core.Method +//import org.http4k.core.Request +//import org.http4k.core.Response +//import org.http4k.core.body.form +//import org.http4k.core.cookie.Cookie +//import org.http4k.core.cookie.cookie +//import org.http4k.core.cookie.cookies +//import org.http4k.core.then +//import org.http4k.filter.ClientFilters +// +// +///* +// * * https://github.com/shanemadden/factorio-mod-portal-publish/blob/master/entrypoint.sh +// * * https://github.com/nicolas-lang/factorio-create-release-action/blob/master/entrypoint.py +// * * https://github.com/nicolas-lang/factorio-create-release-action/blob/master/factorioModPortal.py +// * * https://github.com/justarandomgeek/vscode-factoriomod-debug/blob/master/src/ModPackageProvider.ts#L530 +// * +// * +// */ +//internal class FactorioModPortalClient( +// private val appProps: ApplicationProperties = ApplicationProperties(), +// private val loginFormUrl: String = "https://factorio.com/login?mods=1", +// private val loginUrl: String = "https://factorio.com/login", +//) { +// +// private val client: HttpHandler = +// ClientFilters.FollowRedirects() +// .then(OkHttp()) +// +// private val csrfCookie: Cookie by lazy { fetchCsrfToken() } +// private val sessionCookie: Cookie by lazy { login() } +// +// +// private fun fetchCsrfToken(): Cookie { +// +// val request = Request(Method.GET, loginFormUrl) +// val response: Response = client(request) +// +// val csrfToken = htmlDocument(response.bodyString()) { +// input { +// withId = csrfTokenName +// withAttribute = "name" to csrfTokenName +// findFirst { attribute("value") } +// } +// } +// +// println("csrfToken: $csrfToken") +// return Cookie(csrfTokenName, csrfToken) +// } +// +// +// private fun login(): Cookie { +// +// val loginRequest = Request(Method.POST, loginUrl) +// .header("Referer", loginFormUrl) +//// .cookie(csrfCookie) +// .form("csrf_token", csrfCookie.value) +// .form("username_or_email", appProps.factorioModPortalUsername) +// .form("password", appProps.factorioModPortalPassword.use { it }) +// .form("next_url", "/profile") +// +// val loginResponse = client(loginRequest) +// +// println(loginResponse.bodyString()) +// +// val sessionCookie = loginResponse.cookies() +// .first { it.name == "session" && it.domain == ".factorio.com" } +// +// println("sessionCookie: $sessionCookie") +// +// return sessionCookie +// } +// +// fun getModInfo(modName: String): JsonObject { +// val response = client( +// Request(Method.GET, "https://mods.factorio.com/api/mods/${modName}/full") +// .cookie(csrfCookie) +// .cookie(sessionCookie) +// ) +// return jsonMapper.parseToJsonElement(response.bodyString()).jsonObject +// } +// +// fun fetchModUploadToken(modName: String): String { +// val response = client( +// Request(Method.GET, "https://mods.factorio.com/mod/${modName}/edit") +// .cookie(csrfCookie) +// .cookie(sessionCookie) +// ) +// +// return response.bodyString() +// } +// +// companion object { +// private const val csrfTokenName = "csrf_token" +// } +// +//} diff --git a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalPublishTask.kt b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalPublishTask.kt new file mode 100644 index 0000000..4163228 --- /dev/null +++ b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/FactorioModPortalPublishTask.kt @@ -0,0 +1,83 @@ +package dev.adamko.kafkatorio + +//import javax.inject.Inject +//import kotlinx.coroutines.runBlocking +//import kotlinx.serialization.json.Json +//import net.swiftzer.semver.SemVer +//import okio.FileSystem +//import okio.Path.Companion.toOkioPath +//import okio.Path.Companion.toPath +//import okio.openZip +//import org.gradle.api.DefaultTask +//import org.gradle.api.file.RegularFileProperty +//import org.gradle.api.model.ObjectFactory +//import org.gradle.api.provider.Property +//import org.gradle.api.provider.ProviderFactory +//import org.gradle.api.tasks.Input +//import org.gradle.api.tasks.InputFile +//import org.gradle.api.tasks.TaskAction +//import org.gradle.kotlin.dsl.property +// +// +//abstract class FactorioModPortalPublishTask @Inject constructor( +// objects: ObjectFactory, +// providers: ProviderFactory, +//) : DefaultTask() { +// +// @get:InputFile +// abstract val distributionZip: RegularFileProperty +// +// @get:Input +// abstract val modVersion: Property +// +// @get:Input +// abstract val modName: Property +// +// @get:Input +// abstract val factorioVersion: Property +// +// /** Bearer API key */ +// @get:Input +// val portalApiKey: Property = objects.property().convention( +// providers.gradleProperty("FACTORIO_MOD_PORTAL_API_KEY") +// ) +// +// @get:Input +// val portalUploadEndpoint: Property = objects.property() +// .convention("https://mods.factorio.com/api/v2/mods/releases/init_upload") +// +// +// @TaskAction +// fun deploy() = runBlocking { +// val modVersion = SemVer.parse(modVersion.get()) +// +// val portalUploadEndpoint = portalUploadEndpoint.get() +// val modName = modName.get() +// val portalApiKey = portalApiKey.get() +// val distributionZip = distributionZip.get().asFile +// +// } +// +// private fun validateInfoJson() { +// val modVersion = modVersion.get() +// val factorioVersion = factorioVersion.get() +// +// val distributionZip = distributionZip.get().asFile.toOkioPath() +// +// val zipContents = FileSystem.SYSTEM.openZip(distributionZip) +// +// val infoJson = zipContents.read("info.json".toPath()) { +// generateSequence { readUtf8Line() } +// }.joinToString("\n") +// +// val info: FactorioModInfo = Json.decodeFromString(FactorioModInfo.serializer(), infoJson) +// +// require(info.version == modVersion) { +// "mod version mismatch, ${info.version} vs $modVersion " +// } +// +// require(info.factorioVersion == factorioVersion) { +// "Factorio version mismatch, ${info.factorioVersion} vs $factorioVersion " +// } +// } +//} diff --git a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/modUploader.kt b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/modUploader.kt index 0bb1279..5cba361 100644 --- a/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/modUploader.kt +++ b/modules/factorio-mod-portal-client/src/main/kotlin/dev/adamko/kafkatorio/modUploader.kt @@ -1,14 +1,40 @@ package dev.adamko.kafkatorio - -import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString - - -private const val modName = "kafkatorio-events" - - -fun main() { - val client = FactorioModPortalClient() -// val modInfo = client.getModInfo(modName) -// println(modInfo.asPrettyJsonString()) - println(client.fetchModUploadToken(modName)) -} +// +//import java.io.File +//import kotlinx.cli.ArgParser +//import kotlinx.cli.ArgType +//import kotlinx.cli.required +//import kotlinx.coroutines.runBlocking +// +//fun main(args: Array) = runBlocking { +// val parser = ArgParser("example") +// +// val distributionZip: File by parser.option(FileArg).required() +// val modName: String by parser.option(ArgType.String).required() +// val portalApiKey: String by parser.option(ArgType.String).required() +// val portalUploadEndpoint: String by parser.option(ArgType.String).required() +// +// parser.parse(args) +// +// val client = FactorioModPortalPublishClient( +// distributionZip, +// modName, +// portalApiKey, +// portalUploadEndpoint, +// ) +// +// client.uploadMod() +//} +// +// +//object FileArg : ArgType(true) { +// override val description: kotlin.String +// get() = "{ File }" +// +// override fun convert(value: kotlin.String, name: kotlin.String): File { +// return File(value).also { +// require(it.exists()) { "${it.canonicalPath} does not exist" } +// require(it.isFile) { "${it.canonicalPath} is not a file" } +// } +// } +//} diff --git a/modules/versions-platform/build.gradle.kts b/modules/versions-platform/build.gradle.kts index bb93f8c..1e23afc 100644 --- a/modules/versions-platform/build.gradle.kts +++ b/modules/versions-platform/build.gradle.kts @@ -24,18 +24,12 @@ dependencies { constraints { api(libs.skrapeit) api(libs.kotlinx.serialization.yaml) - - - - - - - - api(libs.kafka.kotkaStreams) api(libs.kafka.streams) api(libs.okio.core) api(libs.scrimage.core) api(libs.kafka.streamsTestUtils) + + api(libs.mockk) } } diff --git a/modules/web-map/build.gradle.kts b/modules/web-map/build.gradle.kts index 0ff58e1..284b406 100644 --- a/modules/web-map/build.gradle.kts +++ b/modules/web-map/build.gradle.kts @@ -36,7 +36,10 @@ kotlin { port = 3000, proxy = mutableMapOf( "/kv/*" to "http://localhost:8080", - "/kvws/*" to mapOf("target" to "ws://localhost:8080", "ws" to true) + "/kvws/*" to mapOf( + "target" to "ws://localhost:8080", + "ws" to true, + ) ), static = mutableListOf("$buildDir/processedResources/frontend/main") ) @@ -160,3 +163,6 @@ fun KotlinDependencyHandler.kvision( // resolution("node-forge", "1.3.0") // } //} + +evaluationDependsOn(rootProject.path) +evaluationDependsOn(projects.modules.eventsSchema.dependencyProject.path) diff --git a/settings.gradle.kts b/settings.gradle.kts index c67af44..0380a2c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,7 +15,7 @@ include( ":modules:kt-rcon", ":modules:web-map", - ":modules:factorio-mod-portal-client", +// ":modules:factorio-mod-portal-client", ":modules:versions-platform", )