Skip to content

Commit

Permalink
feat(server): make it possible to POST custom typings for testing dur…
Browse files Browse the repository at this point in the history
…ing typing creation
  • Loading branch information
Vampire committed Aug 19, 2024
1 parent 5e386d6 commit 2b90ea5
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 26 deletions.
14 changes: 9 additions & 5 deletions action-binding-generator/api/action-binding-generator.api
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ public abstract interface annotation class io/github/typesafegithub/workflows/ac
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
public final fun component4 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;
public fun equals (Ljava/lang/Object;)Z
public final fun getName ()Ljava/lang/String;
public final fun getOwner ()Ljava/lang/String;
public final fun getTypesUuid ()Ljava/lang/String;
public final fun getVersion ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand Down Expand Up @@ -46,6 +49,7 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/dom

public final class io/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource : java/lang/Enum {
public static final field ACTION Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
public static final field CUSTOM Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
public static final field TYPING_CATALOG Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public static fun valueOf (Ljava/lang/String;)Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/TypingActualSource;
Expand All @@ -72,8 +76,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/gen
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/generation/GenerationKt {
public static final fun generateBinding (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;)Ljava/util/List;
public static synthetic fun generateBinding$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;ILjava/lang/Object;)Ljava/util/List;
public static final fun generateBinding (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;Ljava/lang/String;)Ljava/util/List;
public static synthetic fun generateBinding$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;Lkotlin/Pair;Ljava/lang/String;ILjava/lang/Object;)Ljava/util/List;
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public data class ActionCoords(
val owner: String,
val name: String,
val version: String,
val typesUuid: String? = null,
)

/**
Expand All @@ -12,7 +13,7 @@ public data class ActionCoords(
*/
public val ActionCoords.isTopLevel: Boolean get() = "/" !in name

public val ActionCoords.prettyPrint: String get() = "$owner/$name@$version"
public val ActionCoords.prettyPrint: String get() = "$owner/$name@$version${typesUuid?.let { " (types: $it)" } ?: ""}"

/**
* For most actions, it's the same as [ActionCoords.name].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package io.github.typesafegithub.workflows.actionbindinggenerator.domain
public enum class TypingActualSource {
ACTION,
TYPING_CATALOG,
CUSTOM,
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,26 @@ public fun ActionCoords.generateBinding(
metadataRevision: MetadataRevision,
metadata: Metadata? = null,
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
types: String? = null,
): List<ActionBinding> {
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision) ?: return emptyList()
val metadataProcessed = metadataResolved.removeDeprecatedInputsIfNameClash()

val inputTypingsResolved = inputTypings ?: this.provideTypes(metadataRevision)
val (inputTypingsResolved, typingActualSource) =
inputTypings ?: this.provideTypes(metadataRevision, types = types)

val classNameUntyped = this.buildActionClassName() + "_Untyped"
val actionBindingSourceCodeUntyped =
generateActionBindingSourceCode(metadataProcessed, this, emptyMap(), classNameUntyped, untyped = true)

val classNameAndSourceCodeTyped =
if (inputTypingsResolved.second != null) {
if (typingActualSource != null) {
val className = this.buildActionClassName()
val actionBindingSourceCode =
generateActionBindingSourceCode(
metadataProcessed,
this,
inputTypingsResolved.first,
inputTypingsResolved,
className,
untyped = false,
)
Expand All @@ -99,7 +101,7 @@ public fun ActionCoords.generateBinding(
filePath = "io/github/typesafegithub/workflows/actions/$packageName/$className.kt",
className = className,
packageName = packageName,
typingActualSource = inputTypingsResolved.second,
typingActualSource = typingActualSource,
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.github.typesafegithub.workflows.actionbindinggenerator.domain.Metadata
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.NewestForVersion
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.ACTION
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.CUSTOM
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.TypingActualSource.TYPING_CATALOG
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.repoName
import io.github.typesafegithub.workflows.actionbindinggenerator.domain.subName
Expand All @@ -21,10 +22,12 @@ import java.net.URI
internal fun ActionCoords.provideTypes(
metadataRevision: MetadataRevision,
fetchUri: (URI) -> String = ::fetchUri,
types: String? = null,
): Pair<Map<String, Typing>, TypingActualSource?> =
(
this.fetchTypingMetadata(metadataRevision, fetchUri)
?: this.toMajorVersion().fetchFromTypingsFromCatalog(fetchUri)
customTypingMetadata(types)
?: this.fetchTypingMetadata(metadataRevision, fetchUri)
?: this.toMajorVersion().fetchTypingsFromCatalog(fetchUri)
)?.let { Pair(it.first.toTypesMap(), it.second) }
?: Pair(emptyMap(), null)

Expand All @@ -42,6 +45,9 @@ private fun ActionCoords.catalogMetadata() =
private fun ActionCoords.actionTypesYamlUrl(gitRef: String) =
"https://raw.githubusercontent.com/$owner/$repoName/$gitRef$subName/action-types.yaml"

private fun customTypingMetadata(types: String? = null) =
types?.let { Pair(myYaml.decodeFromStringOrDefaultIfEmpty(it, ActionTypes()), CUSTOM) }

private fun ActionCoords.fetchTypingMetadata(
metadataRevision: MetadataRevision,
fetchUri: (URI) -> String = ::fetchUri,
Expand All @@ -65,7 +71,7 @@ private fun ActionCoords.fetchTypingMetadata(
return Pair(myYaml.decodeFromStringOrDefaultIfEmpty(typesMetadataYaml, ActionTypes()), ACTION)
}

private fun ActionCoords.fetchFromTypingsFromCatalog(fetchUri: (URI) -> String = ::fetchUri): Pair<ActionTypes, TypingActualSource>? =
private fun ActionCoords.fetchTypingsFromCatalog(fetchUri: (URI) -> String = ::fetchUri): Pair<ActionTypes, TypingActualSource>? =
(
fetchTypingsFromUrl(url = actionTypesFromCatalog(), fetchUri = fetchUri)
?: fetchTypingsForOlderVersionFromCatalog(fetchUri = fetchUri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ class TypesProvidingTest :
stored-in-typing-catalog:
type: string
""".trimIndent()
val custom =
"""
inputs:
custom:
type: string
""".trimIndent()
val metadata =
"""
"versionsWithTypings":
Expand Down Expand Up @@ -198,6 +204,70 @@ class TypesProvidingTest :
types shouldBe Pair(mapOf("hosted-by-action-yml" to StringTyping), TypingActualSource.ACTION)
}

test("only custom") {
// Given
val fetchUri: (URI) -> String = { throw IOException() }
val actionCoord = ActionCoords("some-owner", "some-name", "v3")

// When
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)

// Then
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
}

test("hosted by action, stored in typing catalog, and custom") {
// Given
val fetchUri: (URI) -> String = {
when (it) {
URI(
"https://raw.githubusercontent.com/some-owner/some-name/" +
"some-hash/action-types.yml",
),
-> hostedByActionYml
URI(
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
"main/typings/some-owner/some-name/v3/action-types.yml",
),
-> storedInTypingCatalog
else -> throw IOException()
}
}
val actionCoord = ActionCoords("some-owner", "some-name", "v3")

// When
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = custom)

// Then
types shouldBe Pair(mapOf("custom" to StringTyping), TypingActualSource.CUSTOM)
}

test("hosted by action, stored in typing catalog, and empty custom") {
// Given
val fetchUri: (URI) -> String = {
when (it) {
URI(
"https://raw.githubusercontent.com/some-owner/some-name/" +
"some-hash/action-types.yml",
),
-> hostedByActionYml
URI(
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
"main/typings/some-owner/some-name/v3/action-types.yml",
),
-> storedInTypingCatalog
else -> throw IOException()
}
}
val actionCoord = ActionCoords("some-owner", "some-name", "v3")

// When
val types = actionCoord.provideTypes(metadataRevision = CommitHash("some-hash"), fetchUri = fetchUri, types = "")

// Then
types shouldBe Pair(emptyMap(), TypingActualSource.CUSTOM)
}

test("only stored in typing catalog for older version") {
// Given
val fetchUri: (URI) -> String = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.request.receiveText
import io.ktor.server.response.respondBytes
import io.ktor.server.response.respondText
import io.ktor.server.routing.Route
import io.ktor.server.routing.get
import io.ktor.server.routing.head
import io.ktor.server.routing.post
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracing
import java.util.UUID.randomUUID
import kotlin.time.Duration.Companion.hours

fun main() {
Expand Down Expand Up @@ -66,7 +69,7 @@ fun main() {
}

get("/status") {
call.respondText("OK")
call.respondText(text = "OK")
}
}
}.start(wait = true)
Expand All @@ -86,7 +89,7 @@ private fun Route.metadata() {
val bindingArtifacts = actionCoords.buildPackageArtifacts(githubToken = getGithubToken())
if (file in bindingArtifacts) {
when (val artifact = bindingArtifacts[file]) {
is String -> call.respondText(artifact)
is String -> call.respondText(text = artifact)
else -> call.respondText(text = "Not found", status = HttpStatusCode.NotFound)
}
} else {
Expand All @@ -102,14 +105,14 @@ private fun Route.artifact(
get {
val bindingArtifacts = call.toBindingArtifacts(bindingsCache, refresh)
if (bindingArtifacts == null) {
call.respondText("Not found", status = HttpStatusCode.NotFound)
call.respondText(text = "Not found", status = HttpStatusCode.NotFound)
return@get
}

val file = call.parameters["file"]!!
if (file in bindingArtifacts) {
when (val artifact = bindingArtifacts[file]) {
is TextArtifact -> call.respondText(artifact.data)
is TextArtifact -> call.respondText(text = artifact.data)
is JarArtifact ->
call.respondBytes(
bytes = artifact.data,
Expand All @@ -127,39 +130,58 @@ private fun Route.artifact(
val bindingArtifacts = call.toBindingArtifacts(bindingsCache, refresh)
val file = call.parameters["file"]!!
if (bindingArtifacts == null) {
call.respondText("Not found", status = HttpStatusCode.NotFound)
call.respondText(text = "Not found", status = HttpStatusCode.NotFound)
return@head
}
if (file in bindingArtifacts) {
call.respondText("Exists", status = HttpStatusCode.OK)
call.respondText(text = "Exists", status = HttpStatusCode.OK)
} else {
call.respondText(text = "Not found", status = HttpStatusCode.NotFound)
}
}

post {
val owner = "${call.parameters["owner"]}__types__${randomUUID()}"
val name = call.parameters["name"]!!
val version = call.parameters["version"]!!
val types = call.receiveText()
call.toBindingArtifacts(bindingsCache, refresh = true, owner = owner, types = types)
call.respondText(text = "$owner:$name:$version")
}
}

private suspend fun ApplicationCall.toBindingArtifacts(
bindingsCache: Cache<ActionCoords, Result<Map<String, Artifact>>>,
refresh: Boolean,
owner: String = parameters["owner"]!!,
types: String? = null,
): Map<String, Artifact>? {
val owner = parameters["owner"]!!
val name = parameters["name"]!!
val version = parameters["version"]!!
val (ownerPlain, typesUuid) =
if (owner.contains("__types__")) {
owner
.split("__types__", limit = 2)
.let { it.first() to it[1] }
} else {
owner to null
}
val actionCoords =
ActionCoords(
owner = owner,
owner = ownerPlain,
name = name,
version = version,
typesUuid = typesUuid,
)
println("➡️ Requesting ${actionCoords.prettyPrint}")
val bindingArtifacts =
if (refresh) {
actionCoords.buildVersionArtifacts().also {
actionCoords.buildVersionArtifacts(types ?: typesUuid?.let { "" }).also {
bindingsCache.put(actionCoords, Result.of(it))
}
} else {
bindingsCache
.get(actionCoords) { Result.of(actionCoords.buildVersionArtifacts()) }
.get(actionCoords) { Result.of(actionCoords.buildVersionArtifacts(types ?: typesUuid?.let { "" })) }
.getOrNull()
}
return bindingArtifacts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ internal fun buildJars(
owner: String,
name: String,
version: String,
types: String?,
): Jars? {
val binding =
generateBinding(owner = owner, name = name, version = version).also {
generateBinding(owner = owner, name = name, version = version, types = types).also {
if (it.isEmpty()) return null
}
val (sourceFilePaths, compilationInputDir) = binding.prepareDirectoryWithSources()
Expand All @@ -54,6 +55,7 @@ private fun generateBinding(
owner: String,
name: String,
version: String,
types: String?,
): List<ActionBinding> {
val actionCoords =
ActionCoords(
Expand All @@ -63,6 +65,7 @@ private fun generateBinding(
)
return actionCoords.generateBinding(
metadataRevision = NewestForVersion,
types = types,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ data class JarArtifact(
val data: ByteArray,
) : Artifact

fun ActionCoords.buildVersionArtifacts(): Map<String, Artifact>? {
val jars = buildJars(owner = owner, name = name.replace("__", "/"), version = version) ?: return null
fun ActionCoords.buildVersionArtifacts(types: String? = null): Map<String, Artifact>? {
val jars = buildJars(owner = owner, name = name.replace("__", "/"), version = version, types = types) ?: return null
val pom = buildPomFile(owner = owner, name = name.replace("__", "/"), version = version)
val module = buildModuleFile(owner = owner, name = name.replace("__", "/"), version = version)
return mapOf(
Expand Down

0 comments on commit 2b90ea5

Please sign in to comment.