add Gradle task to upload the mod to the portal, and some gradle fixes
This commit is contained in:
parent
0f08eee56f
commit
b6b874d8f7
22 changed files with 723 additions and 273 deletions
|
|
@ -4,7 +4,7 @@ plugins {
|
||||||
idea
|
idea
|
||||||
`kotlin-dsl`
|
`kotlin-dsl`
|
||||||
kotlin("jvm") version "1.6.21"
|
kotlin("jvm") version "1.6.21"
|
||||||
`project-report`
|
kotlin("plugin.serialization") version "1.6.21"
|
||||||
}
|
}
|
||||||
|
|
||||||
val gradleJvmTarget = "11"
|
val gradleJvmTarget = "11"
|
||||||
|
|
@ -19,9 +19,12 @@ dependencies {
|
||||||
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
|
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
|
||||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}")
|
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(platform(libs.kotlinx.coroutines.bom))
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core")
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json")
|
|
||||||
|
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.charleskorn.kaml:kaml:0.37.0")
|
||||||
|
|
||||||
implementation("com.github.node-gradle:gradle-node-plugin:${libs.versions.gradleNodePlugin.get()}")
|
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("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
|
// https://github.com/avast/gradle-docker-compose-plugin
|
||||||
// implementation("com.avast.gradle:gradle-docker-compose-plugin:${Versions.gradleDockerComposePlugin}")
|
// implementation("com.avast.gradle:gradle-docker-compose-plugin:${Versions.gradleDockerComposePlugin}")
|
||||||
|
|
||||||
implementation(platform("org.http4k:http4k-bom:${libs.versions.http4k.get()}"))
|
// implementation(platform("org.http4k:http4k-bom:${libs.versions.http4k.get()}"))
|
||||||
implementation("org.http4k:http4k-core")
|
// implementation("org.http4k:http4k-core")
|
||||||
implementation("org.http4k:http4k-client-okhttp")
|
// implementation("org.http4k:http4k-client-okhttp")
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
|
// https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
|
||||||
// https://youtrack.jetbrains.com/issue/IDEA-262280#focus=Comments-27-5397040.0-0
|
// https://youtrack.jetbrains.com/issue/IDEA-262280#focus=Comments-27-5397040.0-0
|
||||||
|
|
@ -63,14 +82,24 @@ tasks.withType<KotlinCompile>().configureEach {
|
||||||
|
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
// "-Xcontext-receivers",
|
// "-Xcontext-receivers",
|
||||||
"-opt-in=kotlin.RequiresOptIn",
|
"-Xopt-in=kotlin.RequiresOptIn",
|
||||||
"-opt-in=kotlin.ExperimentalStdlibApi",
|
"-Xopt-in=kotlin.ExperimentalStdlibApi",
|
||||||
"-opt-in=kotlin.time.ExperimentalTime",
|
"-Xopt-in=kotlin.time.ExperimentalTime",
|
||||||
// "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
// "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
"-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.withType<KotlinCompile>().configureEach {
|
||||||
|
kotlinOptions {
|
||||||
|
apiVersion = gradleKotlinTarget
|
||||||
|
languageVersion = gradleKotlinTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain {
|
jvmToolchain {
|
||||||
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(gradleJvmTarget))
|
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(gradleJvmTarget))
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,10 @@ val jsonMapper = Json {
|
||||||
|
|
||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val kotlinLang = "1.6"
|
|
||||||
const val jvmTarget = "11"
|
|
||||||
|
|
||||||
const val node = "14.19.1"
|
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 kotlinWrappers = "1.0.0-pre.336"
|
||||||
const val junit = "5.8.2"
|
|
||||||
const val kotest = "5.2.3"
|
|
||||||
const val mockk = "1.12.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<String>
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
abstract val modVersion: Property<String>
|
||||||
|
|
||||||
|
// @get:Input
|
||||||
|
// abstract val factorioVersion: Property<String>
|
||||||
|
|
||||||
|
/** Bearer API key */
|
||||||
|
@get:Input
|
||||||
|
val portalApiKey: Property<String> = objects.property<String>().convention(
|
||||||
|
providers.gradleProperty("FACTORIO_MOD_PORTAL_API_KEY")
|
||||||
|
)
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
val portalApiUrl: Property<String> = objects.property<String>()
|
||||||
|
.convention("https://mods.factorio.com/api/v2/")
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
val portalUploadEndpoint: Property<String> = objects.property<String>()
|
||||||
|
.convention("mods/releases/init_upload")
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
group = "factorio"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun deploy() = runBlocking {
|
||||||
|
|
||||||
|
|
||||||
|
val userInputHandler = services.get<UserInputHandler>()
|
||||||
|
|
||||||
|
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 "
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -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>(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>(
|
||||||
|
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<String?, String> = 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<String>,
|
||||||
|
)
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package dev.adamko.kafkatorio.lang
|
package dev.adamko.kafkatorio.lang
|
||||||
|
|
||||||
import dev.adamko.kafkatorio.Versions
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
|
@ -8,33 +7,38 @@ plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val projectKotlinTarget = "1.6"
|
||||||
|
val projectJvmTarget = "11"
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
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")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher") {
|
// testRuntimeOnly("org.junit.platform:junit-platform-launcher") {
|
||||||
because("Only needed to run tests in a version of IntelliJ IDEA that bundles older versions")
|
// 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-runner-junit5")
|
||||||
testImplementation("io.kotest:kotest-assertions-core")
|
testImplementation("io.kotest:kotest-assertions-core")
|
||||||
testImplementation("io.kotest:kotest-property")
|
testImplementation("io.kotest:kotest-property")
|
||||||
testImplementation("io.kotest:kotest-assertions-json")
|
testImplementation("io.kotest:kotest-assertions-json")
|
||||||
|
|
||||||
testImplementation("io.mockk:mockk:${Versions.mockk}")
|
testImplementation("io.mockk:mockk")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile>().configureEach {
|
tasks.withType<KotlinCompile>().configureEach {
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = Versions.jvmTarget
|
jvmTarget = projectJvmTarget
|
||||||
apiVersion = Versions.kotlinLang
|
apiVersion = projectKotlinTarget
|
||||||
languageVersion = Versions.kotlinLang
|
languageVersion = projectKotlinTarget
|
||||||
freeCompilerArgs += listOf(
|
}
|
||||||
|
|
||||||
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
// "-Xcontext-receivers",
|
// "-Xcontext-receivers",
|
||||||
"-opt-in=kotlin.RequiresOptIn",
|
"-opt-in=kotlin.RequiresOptIn",
|
||||||
"-opt-in=kotlin.ExperimentalStdlibApi",
|
"-opt-in=kotlin.ExperimentalStdlibApi",
|
||||||
|
|
@ -43,7 +47,6 @@ tasks.withType<KotlinCompile>().configureEach {
|
||||||
// "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
// "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tasks.compileTestKotlin {
|
tasks.compileTestKotlin {
|
||||||
kotlinOptions.freeCompilerArgs += "-opt-in=io.kotest.common.ExperimentalKotest"
|
kotlinOptions.freeCompilerArgs += "-opt-in=io.kotest.common.ExperimentalKotest"
|
||||||
|
|
@ -51,10 +54,10 @@ tasks.compileTestKotlin {
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain {
|
jvmToolchain {
|
||||||
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(Versions.jvmTarget))
|
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(projectJvmTarget))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test> {
|
tasks.withType<Test>().configureEach {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,6 @@ val updatePackageJson by tasks.registering(UpdatePackageJson::class) {
|
||||||
|
|
||||||
tasks.assemble { dependsOn(updatePackageJson) }
|
tasks.assemble { dependsOn(updatePackageJson) }
|
||||||
|
|
||||||
tasks.withType<NpmInstallTask> {
|
tasks.withType<NpmInstallTask>().configureEach {
|
||||||
dependsOn(updatePackageJson)
|
dependsOn(updatePackageJson)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -22,7 +22,7 @@ object JsonPropertiesUpToDateSpec : ExplainingSpec<Task> {
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|
||||||
val packageJsonContent = packageJsonFile.get().asFile.readText()
|
val packageJsonContent = packageJsonFile2.get().asFile.readText()
|
||||||
val packageJson = jsonMapper.parseToJsonElement(packageJsonContent).jsonObject
|
val packageJson = jsonMapper.parseToJsonElement(packageJsonContent).jsonObject
|
||||||
|
|
||||||
val outdatedProperties = propertiesToCheck.get().mapNotNull { (key, expectedVal) ->
|
val outdatedProperties = propertiesToCheck.get().mapNotNull { (key, expectedVal) ->
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package dev.adamko.kafkatorio.task
|
||||||
|
|
||||||
import com.github.gradle.node.npm.task.NpmTask
|
import com.github.gradle.node.npm.task.NpmTask
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import org.gradle.api.file.ConfigurableFileTree
|
||||||
import org.gradle.api.file.DirectoryProperty
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.file.FileSystemOperations
|
import org.gradle.api.file.FileSystemOperations
|
||||||
import org.gradle.api.plugins.BasePlugin
|
import org.gradle.api.plugins.BasePlugin
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import org.gradle.api.provider.MapProperty
|
||||||
import org.gradle.api.provider.ProviderFactory
|
import org.gradle.api.provider.ProviderFactory
|
||||||
import org.gradle.api.tasks.CacheableTask
|
import org.gradle.api.tasks.CacheableTask
|
||||||
import org.gradle.api.tasks.Input
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.Internal
|
||||||
import org.gradle.api.tasks.OutputFile
|
import org.gradle.api.tasks.OutputFile
|
||||||
import org.gradle.api.tasks.TaskAction
|
import org.gradle.api.tasks.TaskAction
|
||||||
import org.gradle.kotlin.dsl.support.useToRun
|
import org.gradle.kotlin.dsl.support.useToRun
|
||||||
|
|
@ -20,14 +21,15 @@ import org.jetbrains.kotlin.util.suffixIfNot
|
||||||
|
|
||||||
@CacheableTask
|
@CacheableTask
|
||||||
abstract class UpdatePackageJson @Inject constructor(
|
abstract class UpdatePackageJson @Inject constructor(
|
||||||
private val providers: ProviderFactory
|
private val providers: ProviderFactory,
|
||||||
) : DefaultTask() {
|
) : DefaultTask() {
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
abstract val propertiesToCheck: MapProperty<String, String>
|
abstract val propertiesToCheck: MapProperty<String, String>
|
||||||
|
|
||||||
@get:OutputFile
|
// @get:OutputFile
|
||||||
abstract val packageJsonFile: RegularFileProperty
|
@get:Internal
|
||||||
|
abstract val packageJsonFile2: RegularFileProperty
|
||||||
|
|
||||||
init {
|
init {
|
||||||
group = NodePlugin.NODE_GROUP
|
group = NodePlugin.NODE_GROUP
|
||||||
|
|
@ -36,26 +38,37 @@ abstract class UpdatePackageJson @Inject constructor(
|
||||||
|
|
||||||
outputs.upToDateWhen(JsonPropertiesUpToDateSpec)
|
outputs.upToDateWhen(JsonPropertiesUpToDateSpec)
|
||||||
|
|
||||||
super.doFirst {
|
// super.doFirst {
|
||||||
propertiesToCheck.disallowChanges()
|
// propertiesToCheck.disallowChanges()
|
||||||
packageJsonFile.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
|
@TaskAction
|
||||||
fun exec() {
|
fun exec() {
|
||||||
val packageJsonFile = packageJsonFile.asFile.get()
|
val packageJsonFile = packageJsonFile2.asFile.get()
|
||||||
val propertiesToCheck = propertiesToCheck.get()
|
|
||||||
|
|
||||||
logger.info("updating package.json ${packageJsonFile.canonicalPath}")
|
logger.lifecycle("updating package.json ${packageJsonFile.canonicalPath}")
|
||||||
val packageJson = jsonMapper.parseToJsonElement(packageJsonFile.readText()).jsonObject
|
|
||||||
|
|
||||||
val newJsonProps = propertiesToCheck.mapValues { (_, newVal) -> JsonPrimitive(newVal) }
|
val currentPackageJson = currentPackageJson()
|
||||||
|
val updatedPackageJson = updatedPackageJson(currentPackageJson)
|
||||||
|
|
||||||
val packageJsonUpdate = JsonObject(packageJson + newJsonProps)
|
|
||||||
val packageJsonContentUpdated =
|
val packageJsonContentUpdated =
|
||||||
jsonMapper
|
jsonMapper
|
||||||
.encodeToString(packageJsonUpdate)
|
.encodeToString(updatedPackageJson)
|
||||||
.suffixIfNot("\n")
|
.suffixIfNot("\n")
|
||||||
|
|
||||||
logger.debug(packageJsonContentUpdated)
|
logger.debug(packageJsonContentUpdated)
|
||||||
|
|
@ -64,4 +77,15 @@ abstract class UpdatePackageJson @Inject constructor(
|
||||||
write(packageJsonContentUpdated)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ kotlinJsWrappers = "0.0.1-pre.334"
|
||||||
kotlinx-html = "0.7.5"
|
kotlinx-html = "0.7.5"
|
||||||
kotlinx-nodejs = "0.0.7"
|
kotlinx-nodejs = "0.0.7"
|
||||||
kotlinx-coroutines = "1.6.1"
|
kotlinx-coroutines = "1.6.1"
|
||||||
|
kotlinx-cli = "0.3.4"
|
||||||
|
|
||||||
ktor = "2.0.1"
|
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-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-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" }
|
kotlin-jsWrappers-bom = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-wrappers-bom", version.ref = "kotlinJsWrappers" }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## http4k ##
|
## http4k ##
|
||||||
http4k-bom = { group = "org.http4k", name = "http4k-bom", version.ref = "http4k" }
|
http4k-bom = { group = "org.http4k", name = "http4k-bom", version.ref = "http4k" }
|
||||||
http4k-core = { group = "org.http4k", name = "http4k-core" }
|
http4k-core = { group = "org.http4k", name = "http4k-core" }
|
||||||
|
|
@ -88,9 +92,9 @@ http4k-client-okhttp = { group = "org.http4k", name = "http4k-client-okhttp"
|
||||||
http4k-client-ws = { group = "org.http4k", name = "http4k-client-websocket" }
|
http4k-client-ws = { group = "org.http4k", name = "http4k-client-websocket" }
|
||||||
http4k-server = { group = "org.http4k", name = "http4k-server-undertow" }
|
http4k-server = { group = "org.http4k", name = "http4k-server-undertow" }
|
||||||
http4k-cloudnative = { group = "org.http4k", name = "http4k-cloudnative" }
|
http4k-cloudnative = { group = "org.http4k", name = "http4k-cloudnative" }
|
||||||
http4k-format-json = { group = "org.http4k", name = "http4k-format-jackson" }
|
#http4k-format-jackson-json = { group = "org.http4k", name = "http4k-format-jackson" }
|
||||||
http4k-format-xml = { group = "org.http4k", name = "http4k-format-jackson-xml" }
|
#http4k-format-jackson-xml = { group = "org.http4k", name = "http4k-format-jackson-xml" }
|
||||||
http4k-format-yaml = { group = "org.http4k", name = "http4k-format-jackson-yaml" }
|
#http4k-format-jackson-yaml = { group = "org.http4k", name = "http4k-format-jackson-yaml" }
|
||||||
http4k-format-kotlinx = { group = "org.http4k", name = "http4k-format-kotlinx-serialization" }
|
http4k-format-kotlinx = { group = "org.http4k", name = "http4k-format-kotlinx-serialization" }
|
||||||
http4k-graphql = { group = "org.http4k", name = "http4k-graphql" }
|
http4k-graphql = { group = "org.http4k", name = "http4k-graphql" }
|
||||||
|
|
||||||
|
|
@ -98,6 +102,17 @@ http4k-graphql = { group = "org.http4k", name = "http4k-graphql"
|
||||||
## ktor ##
|
## 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 ##
|
||||||
#jackson-bom = { group = " com.fasterxml.jackson.module", name = ":jackson-module-kotlin", version = "2.13.+" }
|
#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" }
|
scrimage-core = { group = "com.sksamuel.scrimage", name = "scrimage-core", version.ref = "scrimage" }
|
||||||
|
|
||||||
|
semver = { group = "net.swiftzer.semver", name = "semver", version.ref = "semver" }
|
||||||
|
|
||||||
## okio ##
|
## okio ##
|
||||||
okio-bom = { group = "com.squareup.okio", name = "okio-bom", version.ref = "okio" }
|
okio-bom = { group = "com.squareup.okio", name = "okio-bom", version.ref = "okio" }
|
||||||
|
|
@ -194,9 +210,9 @@ http4k = [
|
||||||
"http4k-client-ws",
|
"http4k-client-ws",
|
||||||
"http4k-server",
|
"http4k-server",
|
||||||
"http4k-cloudnative",
|
"http4k-cloudnative",
|
||||||
"http4k-format-xml",
|
# "http4k-format-jackson-xml",
|
||||||
"http4k-format-json",
|
# "http4k-format-jackson-json",
|
||||||
"http4k-format-yaml",
|
# "http4k-format-jackson-yaml",
|
||||||
"http4k-format-kotlinx",
|
"http4k-format-kotlinx",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import dev.adamko.kafkatorio.factoriomod.FactorioModPublishTask
|
||||||
import dev.adamko.kafkatorio.gradle.asConsumer
|
import dev.adamko.kafkatorio.gradle.asConsumer
|
||||||
import dev.adamko.kafkatorio.gradle.asProvider
|
import dev.adamko.kafkatorio.gradle.asProvider
|
||||||
import dev.adamko.kafkatorio.gradle.dropDirectories
|
import dev.adamko.kafkatorio.gradle.dropDirectories
|
||||||
|
|
@ -50,7 +51,7 @@ val tsSrcDir: Directory = layout.projectDirectory.dir("src/main/typescript")
|
||||||
|
|
||||||
|
|
||||||
node {
|
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 {
|
distributions {
|
||||||
main {
|
main {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ description = """
|
||||||
|
|
||||||
val projectId: String by project.extra
|
val projectId: String by project.extra
|
||||||
|
|
||||||
val kafkaStateDir = layout.projectDirectory.dir("kafka-state")
|
val kafkaStateDir: Directory = layout.projectDirectory.dir("kafka-state")
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform(projects.modules.versionsPlatform))
|
implementation(platform(projects.modules.versionsPlatform))
|
||||||
|
|
@ -64,7 +64,7 @@ application {
|
||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile>().configureEach {
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,41 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
plugins {
|
plugins {
|
||||||
dev.adamko.kafkatorio.lang.`kotlin-jvm`
|
dev.adamko.kafkatorio.lang.`kotlin-jvm`
|
||||||
kotlin("plugin.serialization")
|
kotlin("plugin.serialization")
|
||||||
application
|
`java-gradle-plugin`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform(projects.modules.versionsPlatform))
|
implementation(platform(projects.modules.versionsPlatform))
|
||||||
|
|
||||||
implementation(projects.modules.eventsServer)
|
// implementation(gradleKotlinDsl())
|
||||||
|
|
||||||
implementation(libs.kotlinx.serialization.core)
|
implementation(libs.kotlinx.serialization.core)
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
implementation(libs.kotlinx.cli)
|
||||||
|
|
||||||
implementation(libs.kotlinx.coroutines.core)
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
|
||||||
implementation(libs.bundles.http4k)
|
// implementation(libs.bundles.http4k)
|
||||||
implementation(libs.http4k.format.kotlinx)
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
tasks.withType<KotlinCompile>().configureEach {
|
||||||
//application {
|
|
||||||
// mainClass.set("dev.adamko.kafkatorio.processor.EventProcessorKt")
|
|
||||||
//}
|
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||||
|
|
|
||||||
|
|
@ -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]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +1,107 @@
|
||||||
package dev.adamko.kafkatorio
|
package dev.adamko.kafkatorio
|
||||||
|
|
||||||
import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString
|
//import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString
|
||||||
import dev.adamko.kafkatorio.processor.serdes.jsonMapper
|
//import dev.adamko.kafkatorio.processor.serdes.jsonMapper
|
||||||
import it.skrape.core.htmlDocument
|
//import it.skrape.core.htmlDocument
|
||||||
import it.skrape.selects.html5.input
|
//import it.skrape.selects.html5.input
|
||||||
import kotlinx.serialization.json.JsonObject
|
//import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.jsonObject
|
//import kotlinx.serialization.json.jsonObject
|
||||||
import org.http4k.client.OkHttp
|
//import org.http4k.client.OkHttp
|
||||||
import org.http4k.core.HttpHandler
|
//import org.http4k.core.HttpHandler
|
||||||
import org.http4k.core.Method
|
//import org.http4k.core.Method
|
||||||
import org.http4k.core.Request
|
//import org.http4k.core.Request
|
||||||
import org.http4k.core.Response
|
//import org.http4k.core.Response
|
||||||
import org.http4k.core.body.form
|
//import org.http4k.core.body.form
|
||||||
import org.http4k.core.cookie.Cookie
|
//import org.http4k.core.cookie.Cookie
|
||||||
import org.http4k.core.cookie.cookie
|
//import org.http4k.core.cookie.cookie
|
||||||
import org.http4k.core.cookie.cookies
|
//import org.http4k.core.cookie.cookies
|
||||||
import org.http4k.core.then
|
//import org.http4k.core.then
|
||||||
import org.http4k.filter.ClientFilters
|
//import org.http4k.filter.ClientFilters
|
||||||
|
//
|
||||||
|
//
|
||||||
/**
|
///*
|
||||||
* * https://github.com/shanemadden/factorio-mod-portal-publish/blob/master/entrypoint.sh
|
// * * 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/entrypoint.py
|
||||||
* * https://github.com/nicolas-lang/factorio-create-release-action/blob/master/factorioModPortal.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
|
// * * https://github.com/justarandomgeek/vscode-factoriomod-debug/blob/master/src/ModPackageProvider.ts#L530
|
||||||
*
|
// *
|
||||||
*
|
// *
|
||||||
*/
|
// */
|
||||||
internal class FactorioModPortalClient(
|
//internal class FactorioModPortalClient(
|
||||||
private val appProps: ApplicationProperties = ApplicationProperties(),
|
// private val appProps: ApplicationProperties = ApplicationProperties(),
|
||||||
private val loginFormUrl: String = "https://factorio.com/login?mods=1",
|
// private val loginFormUrl: String = "https://factorio.com/login?mods=1",
|
||||||
private val loginUrl: String = "https://factorio.com/login",
|
// private val loginUrl: String = "https://factorio.com/login",
|
||||||
) {
|
//) {
|
||||||
|
//
|
||||||
private val client: HttpHandler =
|
// private val client: HttpHandler =
|
||||||
ClientFilters.FollowRedirects()
|
// ClientFilters.FollowRedirects()
|
||||||
.then(OkHttp())
|
// .then(OkHttp())
|
||||||
|
//
|
||||||
private val csrfCookie: Cookie by lazy { fetchCsrfToken() }
|
// private val csrfCookie: Cookie by lazy { fetchCsrfToken() }
|
||||||
private val sessionCookie: Cookie by lazy { login() }
|
// private val sessionCookie: Cookie by lazy { login() }
|
||||||
|
//
|
||||||
|
//
|
||||||
private fun fetchCsrfToken(): Cookie {
|
// private fun fetchCsrfToken(): Cookie {
|
||||||
|
//
|
||||||
val request = Request(Method.GET, loginFormUrl)
|
// val request = Request(Method.GET, loginFormUrl)
|
||||||
val response: Response = client(request)
|
// val response: Response = client(request)
|
||||||
|
//
|
||||||
val csrfToken = htmlDocument(response.bodyString()) {
|
// val csrfToken = htmlDocument(response.bodyString()) {
|
||||||
input {
|
// input {
|
||||||
withId = csrfTokenName
|
// withId = csrfTokenName
|
||||||
withAttribute = "name" to csrfTokenName
|
// withAttribute = "name" to csrfTokenName
|
||||||
findFirst { attribute("value") }
|
// findFirst { attribute("value") }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
println("csrfToken: $csrfToken")
|
// println("csrfToken: $csrfToken")
|
||||||
return Cookie(csrfTokenName, csrfToken)
|
// return Cookie(csrfTokenName, csrfToken)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
private fun login(): Cookie {
|
// private fun login(): Cookie {
|
||||||
|
//
|
||||||
val loginRequest = Request(Method.POST, loginUrl)
|
// val loginRequest = Request(Method.POST, loginUrl)
|
||||||
.header("Referer", loginFormUrl)
|
// .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(csrfCookie)
|
||||||
.form("csrf_token", csrfCookie.value)
|
// .cookie(sessionCookie)
|
||||||
.form("username_or_email", appProps.factorioModPortalUsername)
|
// )
|
||||||
.form("password", appProps.factorioModPortalPassword.use { it })
|
// return jsonMapper.parseToJsonElement(response.bodyString()).jsonObject
|
||||||
.form("next_url", "/profile")
|
// }
|
||||||
|
//
|
||||||
val loginResponse = client(loginRequest)
|
// fun fetchModUploadToken(modName: String): String {
|
||||||
|
// val response = client(
|
||||||
println(loginResponse.bodyString())
|
// Request(Method.GET, "https://mods.factorio.com/mod/${modName}/edit")
|
||||||
|
// .cookie(csrfCookie)
|
||||||
val sessionCookie = loginResponse.cookies()
|
// .cookie(sessionCookie)
|
||||||
.first { it.name == "session" && it.domain == ".factorio.com" }
|
// )
|
||||||
|
//
|
||||||
println("sessionCookie: $sessionCookie")
|
// return response.bodyString()
|
||||||
|
// }
|
||||||
return sessionCookie
|
//
|
||||||
}
|
// companion object {
|
||||||
|
// private const val csrfTokenName = "csrf_token"
|
||||||
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"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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<String>
|
||||||
|
//
|
||||||
|
// @get:Input
|
||||||
|
// abstract val modName: Property<String>
|
||||||
|
//
|
||||||
|
// @get:Input
|
||||||
|
// abstract val factorioVersion: Property<String>
|
||||||
|
//
|
||||||
|
// /** Bearer API key */
|
||||||
|
// @get:Input
|
||||||
|
// val portalApiKey: Property<String> = objects.property<String>().convention(
|
||||||
|
// providers.gradleProperty("FACTORIO_MOD_PORTAL_API_KEY")
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// @get:Input
|
||||||
|
// val portalUploadEndpoint: Property<String> = objects.property<String>()
|
||||||
|
// .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 "
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
@ -1,14 +1,40 @@
|
||||||
package dev.adamko.kafkatorio
|
package dev.adamko.kafkatorio
|
||||||
|
//
|
||||||
import dev.adamko.kafkatorio.processor.serdes.KXS.asPrettyJsonString
|
//import java.io.File
|
||||||
|
//import kotlinx.cli.ArgParser
|
||||||
|
//import kotlinx.cli.ArgType
|
||||||
private const val modName = "kafkatorio-events"
|
//import kotlinx.cli.required
|
||||||
|
//import kotlinx.coroutines.runBlocking
|
||||||
|
//
|
||||||
fun main() {
|
//fun main(args: Array<String>) = runBlocking {
|
||||||
val client = FactorioModPortalClient()
|
// val parser = ArgParser("example")
|
||||||
// val modInfo = client.getModInfo(modName)
|
//
|
||||||
// println(modInfo.asPrettyJsonString())
|
// val distributionZip: File by parser.option(FileArg).required()
|
||||||
println(client.fetchModUploadToken(modName))
|
// 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<File>(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" }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -24,18 +24,12 @@ dependencies {
|
||||||
constraints {
|
constraints {
|
||||||
api(libs.skrapeit)
|
api(libs.skrapeit)
|
||||||
api(libs.kotlinx.serialization.yaml)
|
api(libs.kotlinx.serialization.yaml)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
api(libs.kafka.kotkaStreams)
|
api(libs.kafka.kotkaStreams)
|
||||||
api(libs.kafka.streams)
|
api(libs.kafka.streams)
|
||||||
api(libs.okio.core)
|
api(libs.okio.core)
|
||||||
api(libs.scrimage.core)
|
api(libs.scrimage.core)
|
||||||
api(libs.kafka.streamsTestUtils)
|
api(libs.kafka.streamsTestUtils)
|
||||||
|
|
||||||
|
api(libs.mockk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,10 @@ kotlin {
|
||||||
port = 3000,
|
port = 3000,
|
||||||
proxy = mutableMapOf(
|
proxy = mutableMapOf(
|
||||||
"/kv/*" to "http://localhost:8080",
|
"/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")
|
static = mutableListOf("$buildDir/processedResources/frontend/main")
|
||||||
)
|
)
|
||||||
|
|
@ -160,3 +163,6 @@ fun KotlinDependencyHandler.kvision(
|
||||||
// resolution("node-forge", "1.3.0")
|
// resolution("node-forge", "1.3.0")
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
evaluationDependsOn(rootProject.path)
|
||||||
|
evaluationDependsOn(projects.modules.eventsSchema.dependencyProject.path)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ include(
|
||||||
":modules:kt-rcon",
|
":modules:kt-rcon",
|
||||||
":modules:web-map",
|
":modules:web-map",
|
||||||
|
|
||||||
":modules:factorio-mod-portal-client",
|
// ":modules:factorio-mod-portal-client",
|
||||||
|
|
||||||
":modules:versions-platform",
|
":modules:versions-platform",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue