Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): make it possible to POST custom typings for testing during typing creation #1602

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions action-binding-generator/api/action-binding-generator.api
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
public final class io/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords {
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 fun <init> (Ljava/lang/String;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;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 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 final fun component5 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;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;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 getPath ()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 +48,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 +75,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/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;Ljava/lang/String;ILjava/lang/Object;)Ljava/util/List;
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/Input {
Expand Down Expand Up @@ -146,8 +149,8 @@ public final class io/github/typesafegithub/workflows/actionbindinggenerator/met
}

public final class io/github/typesafegithub/workflows/actionbindinggenerator/metadata/MetadataReadingKt {
public static final fun fetchMetadata (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;
public static synthetic fun fetchMetadata$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;
public static final fun fetchMetadata (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;
public static synthetic fun fetchMetadata$default (Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/ActionCoords;Lio/github/typesafegithub/workflows/actionbindinggenerator/domain/MetadataRevision;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/actionbindinggenerator/metadata/Metadata;
}

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

/**
Expand All @@ -13,7 +14,7 @@ public data class ActionCoords(
*/
public val ActionCoords.isTopLevel: Boolean get() = path == null

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

/**
* For most actions, it's empty.
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 @@ -61,11 +61,14 @@ public fun ActionCoords.generateBinding(
metadataRevision: MetadataRevision,
metadata: Metadata? = null,
inputTypings: Pair<Map<String, Typing>, TypingActualSource?>? = null,
types: String? = null,
explicitMetadata: String? = null,
): List<ActionBinding> {
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision) ?: return emptyList()
val metadataResolved = metadata ?: this.fetchMetadata(metadataRevision, explicitMetadata) ?: return emptyList()
val metadataProcessed = metadataResolved.removeDeprecatedInputsIfNameClash()

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

val packageName = owner.toKotlinPackageName()
val className = this.buildActionClassName()
Expand All @@ -78,7 +81,7 @@ public fun ActionCoords.generateBinding(
emptyMap(),
classNameUntyped,
untypedClass = true,
replaceWith = inputTypingsResolved.second?.let { CodeBlock.of("ReplaceWith(%S)", className) },
replaceWith = typingActualSource?.let { CodeBlock.of("ReplaceWith(%S)", className) },
)

return listOfNotNull(
Expand All @@ -89,12 +92,12 @@ public fun ActionCoords.generateBinding(
packageName = packageName,
typingActualSource = null,
),
inputTypingsResolved.second?.let {
typingActualSource?.let {
val actionBindingSourceCode =
generateActionBindingSourceCode(
metadata = metadataProcessed,
coords = this,
inputTypings = inputTypingsResolved.first,
inputTypings = inputTypingsResolved,
className = className,
)
ActionBinding(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ private fun ActionCoords.actionYamlUrl(gitRef: String) = "https://raw.githubuser

public fun ActionCoords.fetchMetadata(
metadataRevision: MetadataRevision,
explicitMetadata: String? = null,
fetchUri: (URI) -> String = ::fetchUri,
): Metadata? {
if (explicitMetadata != null) {
return yaml.decodeFromString(explicitMetadata)
}

val gitRef =
when (metadataRevision) {
is CommitHash -> metadataRevision.value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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.subName
import io.github.typesafegithub.workflows.actionbindinggenerator.metadata.fetchUri
Expand All @@ -24,10 +25,12 @@ private val logger = logger { }
internal fun ActionCoords.provideTypes(
metadataRevision: MetadataRevision,
fetchUri: (URI) -> String = ::fetchUri,
types: String? = null,
Comment on lines 27 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can make it better - adding types looks like a carveout in this function, and implies some hacks across the project like adding typesUuid to ActionCoords. I'd expect that just parsing of the YAML is triggered if the types as string are provided. I'll think about how to structure it better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "carveout"?

It says "give me the types, here is the YAML to use, if I don't give one explicitly default to requesting them from the action or catalog". For me this is not a "carveout" unless I don't get what you mean.

I also do not really see what "hacks" you mean. The "typesUuid" for me is not a hack but a generated part of the coordinates. It also is part of the coordinates, it is just split once and then stored into a separate field.

): 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 @@ -45,6 +48,9 @@ private fun ActionCoords.catalogMetadata() =
private fun ActionCoords.actionTypesYamlUrl(gitRef: String) =
"https://raw.githubusercontent.com/$owner/$name/$gitRef$subName/action-types.yaml"

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

private fun ActionCoords.fetchTypingMetadata(
metadataRevision: MetadataRevision,
fetchUri: (URI) -> String = ::fetchUri,
Expand All @@ -68,7 +74,7 @@ private fun ActionCoords.fetchTypingMetadata(
return Pair(yaml.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 @@ -151,6 +151,12 @@ class TypesProvidingTest :
stored-in-typing-catalog:
type: string
""".trimIndent()
val custom =
"""
inputs:
custom:
type: string
""".trimIndent()
val metadata =
"""
"versionsWithTypings":
Expand Down Expand Up @@ -375,6 +381,134 @@ 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("only custom for subaction") {
// Given
val fetchUri: (URI) -> String = { throw IOException() }
val actionCoord = ActionCoords("some-owner", "some-name", "v3", "some-sub")

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

// 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("hosted by subaction, 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/some-sub/action-types.yml",
),
-> hostedByActionYml
URI(
"https://raw.githubusercontent.com/typesafegithub/github-actions-typing-catalog/" +
"main/typings/some-owner/some-name/v3/some-sub/action-types.yml",
),
-> storedInTypingCatalog
else -> throw IOException()
}
}
val actionCoord = ActionCoords("some-owner", "some-name", "v3", "some-sub")

// 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 Expand Up @@ -575,6 +709,26 @@ class TypesProvidingTest :
)
}

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 = typingYml)

// Then
types shouldBe
Pair(
mapOf(
"granted-scopes" to ListOfTypings(",", EnumTyping("GrantedScopes", listOf("read", "write"))),
"granted-scopes2" to ListOfTypings(",", EnumTyping("GrantedScopes", listOf("read", "write"))),
"granted-scopes3" to ListOfTypings("""\n""", EnumTyping("GrantedScopes", listOf("read", "write"))),
),
TypingActualSource.CUSTOM,
)
}

test("billion laughs attack is prevented") {
// Given
val billionLaughsAttack =
Expand Down
Loading
Loading