Skip to content

Commit 3f120c6

Browse files
authored
feat(dsl): provide minimal github context in Kotlin logic step (#1406)
A step towards being able to access any context from within the Kotlin-based logic step.
1 parent 415fd15 commit 3f120c6

File tree

8 files changed

+151
-14
lines changed

8 files changed

+151
-14
lines changed

github-workflows-kt/api/github-workflows-kt.api

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,11 @@ public final class io/github/typesafegithub/workflows/domain/JobOutputs$Ref : ko
215215
}
216216

217217
public final class io/github/typesafegithub/workflows/domain/KotlinLogicStep : io/github/typesafegithub/workflows/domain/Step {
218-
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;)V
219-
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
218+
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)V
219+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
220220
public final fun component1 ()Ljava/lang/String;
221221
public final fun component10 ()Ljava/util/Map;
222-
public final fun component11 ()Lkotlin/jvm/functions/Function0;
222+
public final fun component11 ()Lkotlin/jvm/functions/Function1;
223223
public final fun component2 ()Ljava/lang/String;
224224
public final fun component3 ()Ljava/lang/String;
225225
public final fun component4 ()Ljava/util/LinkedHashMap;
@@ -228,15 +228,15 @@ public final class io/github/typesafegithub/workflows/domain/KotlinLogicStep : i
228228
public final fun component7 ()Ljava/lang/Integer;
229229
public final fun component8 ()Lio/github/typesafegithub/workflows/domain/Shell;
230230
public final fun component9 ()Ljava/lang/String;
231-
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
232-
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
231+
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
232+
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
233233
public fun equals (Ljava/lang/Object;)Z
234234
public final fun getCommand ()Ljava/lang/String;
235235
public fun getCondition ()Ljava/lang/String;
236236
public fun getContinueOnError ()Ljava/lang/Boolean;
237237
public fun getEnv ()Ljava/util/LinkedHashMap;
238238
public fun getId ()Ljava/lang/String;
239-
public final fun getLogic ()Lkotlin/jvm/functions/Function0;
239+
public final fun getLogic ()Lkotlin/jvm/functions/Function1;
240240
public final fun getName ()Ljava/lang/String;
241241
public final fun getShell ()Lio/github/typesafegithub/workflows/domain/Shell;
242242
public fun getTimeoutMinutes ()Ljava/lang/Integer;
@@ -600,6 +600,80 @@ public abstract class io/github/typesafegithub/workflows/domain/actions/RegularA
600600
public fun getActionVersion ()Ljava/lang/String;
601601
}
602602

603+
public final class io/github/typesafegithub/workflows/domain/contexts/Contexts {
604+
public fun <init> (Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;)V
605+
public final fun component1 ()Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;
606+
public final fun copy (Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;)Lio/github/typesafegithub/workflows/domain/contexts/Contexts;
607+
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/domain/contexts/Contexts;Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/contexts/Contexts;
608+
public fun equals (Ljava/lang/Object;)Z
609+
public final fun getGithub ()Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;
610+
public fun hashCode ()I
611+
public fun toString ()Ljava/lang/String;
612+
}
613+
614+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContext {
615+
public static final field Companion Lio/github/typesafegithub/workflows/domain/contexts/GithubContext$Companion;
616+
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;Ljava/lang/String;)V
617+
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
618+
public final fun component1 ()Ljava/lang/String;
619+
public final fun component2 ()Ljava/lang/String;
620+
public final fun component3 ()Ljava/lang/String;
621+
public final fun component4 ()Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;
622+
public final fun component5 ()Ljava/lang/String;
623+
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;Ljava/lang/String;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;
624+
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;
625+
public fun equals (Ljava/lang/Object;)Z
626+
public final fun getEvent ()Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;
627+
public final fun getEvent_name ()Ljava/lang/String;
628+
public final fun getRef ()Ljava/lang/String;
629+
public final fun getRepository ()Ljava/lang/String;
630+
public final fun getSha ()Ljava/lang/String;
631+
public fun hashCode ()I
632+
public fun toString ()Ljava/lang/String;
633+
}
634+
635+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContext$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
636+
public static final field INSTANCE Lio/github/typesafegithub/workflows/domain/contexts/GithubContext$$serializer;
637+
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
638+
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;
639+
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
640+
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
641+
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/github/typesafegithub/workflows/domain/contexts/GithubContext;)V
642+
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
643+
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
644+
}
645+
646+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContext$Companion {
647+
public final fun serializer ()Lkotlinx/serialization/KSerializer;
648+
}
649+
650+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContextEvent {
651+
public static final field Companion Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent$Companion;
652+
public fun <init> (Ljava/lang/String;)V
653+
public final fun component1 ()Ljava/lang/String;
654+
public final fun copy (Ljava/lang/String;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;
655+
public static synthetic fun copy$default (Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;Ljava/lang/String;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;
656+
public fun equals (Ljava/lang/Object;)Z
657+
public final fun getAfter ()Ljava/lang/String;
658+
public fun hashCode ()I
659+
public fun toString ()Ljava/lang/String;
660+
}
661+
662+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContextEvent$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
663+
public static final field INSTANCE Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent$$serializer;
664+
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
665+
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;
666+
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
667+
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
668+
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/github/typesafegithub/workflows/domain/contexts/GithubContextEvent;)V
669+
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
670+
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
671+
}
672+
673+
public final class io/github/typesafegithub/workflows/domain/contexts/GithubContextEvent$Companion {
674+
public final fun serializer ()Lkotlinx/serialization/KSerializer;
675+
}
676+
603677
public final class io/github/typesafegithub/workflows/domain/triggers/BranchProtectionRule : io/github/typesafegithub/workflows/domain/triggers/Trigger {
604678
public static final field Companion Lio/github/typesafegithub/workflows/domain/triggers/BranchProtectionRule$Companion;
605679
public fun <init> ()V
@@ -1805,9 +1879,9 @@ public final class io/github/typesafegithub/workflows/dsl/JobBuilder : io/github
18051879
public final fun getTimeoutMinutes ()Ljava/lang/Integer;
18061880
public fun get_customArguments ()Ljava/util/Map;
18071881
public final fun run ([Lkotlin/Unit;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;)Lio/github/typesafegithub/workflows/domain/CommandStep;
1808-
public final fun run ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
1882+
public final fun run ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
18091883
public static synthetic fun run$default (Lio/github/typesafegithub/workflows/dsl/JobBuilder;[Lkotlin/Unit;Ljava/lang/String;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/CommandStep;
1810-
public static synthetic fun run$default (Lio/github/typesafegithub/workflows/dsl/JobBuilder;[Lkotlin/Unit;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
1884+
public static synthetic fun run$default (Lio/github/typesafegithub/workflows/dsl/JobBuilder;[Lkotlin/Unit;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Shell;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/KotlinLogicStep;
18111885
public final fun uses ([Lkotlin/Unit;Lio/github/typesafegithub/workflows/domain/actions/Action;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/util/Map;)Lio/github/typesafegithub/workflows/domain/ActionStep;
18121886
public static synthetic fun uses$default (Lio/github/typesafegithub/workflows/dsl/JobBuilder;[Lkotlin/Unit;Lio/github/typesafegithub/workflows/domain/actions/Action;Ljava/lang/String;Ljava/util/LinkedHashMap;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Integer;Ljava/util/Map;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/ActionStep;
18131887
}

github-workflows-kt/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ version = rootProject.version
2121
dependencies {
2222
implementation("it.krzeminski:snakeyaml-engine-kmp:2.7.5")
2323
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3")
24+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
2425
implementation(projects.sharedInternal)
2526

26-
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
2727
testImplementation("dev.zacsweers.kctfork:core:0.4.1")
2828
testImplementation("com.lemonappdev:konsist:0.14.0")
2929
// Needed to use the right version of the compiler for the libraries that depend on it.

github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/domain/Step.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.github.typesafegithub.workflows.domain
22

33
import io.github.typesafegithub.workflows.domain.actions.Action
44
import io.github.typesafegithub.workflows.domain.actions.Action.Outputs
5+
import io.github.typesafegithub.workflows.domain.contexts.Contexts
56
import io.github.typesafegithub.workflows.dsl.HasCustomArguments
67
import kotlinx.serialization.Contextual
78

@@ -56,7 +57,7 @@ public data class KotlinLogicStep(
5657
val shell: Shell? = null,
5758
val workingDirectory: String? = null,
5859
override val _customArguments: Map<String, @Contextual Any?> = emptyMap(),
59-
val logic: () -> Unit,
60+
val logic: Contexts.() -> Unit,
6061
) : Step(
6162
id = id,
6263
condition = condition,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.github.typesafegithub.workflows.domain.contexts
2+
3+
public data class Contexts(
4+
val github: GithubContext,
5+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@file:Suppress("ConstructorParameterNaming")
2+
3+
package io.github.typesafegithub.workflows.domain.contexts
4+
5+
import kotlinx.serialization.Serializable
6+
7+
@Serializable
8+
public data class GithubContext(
9+
val repository: String,
10+
val sha: String,
11+
val ref: String? = null,
12+
val event: GithubContextEvent,
13+
val event_name: String,
14+
)
15+
16+
@Serializable
17+
public data class GithubContextEvent(
18+
val after: String?,
19+
)

github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/dsl/JobBuilder.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.github.typesafegithub.workflows.domain.Permission
1414
import io.github.typesafegithub.workflows.domain.RunnerType
1515
import io.github.typesafegithub.workflows.domain.Shell
1616
import io.github.typesafegithub.workflows.domain.actions.Action
17+
import io.github.typesafegithub.workflows.domain.contexts.Contexts
1718
import kotlinx.serialization.Contextual
1819
import kotlin.io.path.name
1920

@@ -109,7 +110,7 @@ public class JobBuilder<OUTPUT : JobOutputs>(
109110
workingDirectory: String? = null,
110111
@SuppressWarnings("FunctionParameterNaming")
111112
_customArguments: Map<String, @Contextual Any> = mapOf(),
112-
logic: () -> Unit,
113+
logic: Contexts.() -> Unit,
113114
): KotlinLogicStep {
114115
require(!(`if` != null && condition != null)) {
115116
"Either 'if' or 'condition' have to be set, not both!"
@@ -131,7 +132,7 @@ public class JobBuilder<OUTPUT : JobOutputs>(
131132
// simplified implementation is used.
132133
command = "GHWKT_RUN_STEP='${this.id}:$id' '.github/workflows/${sourceFile.name}'",
133134
logic = logic,
134-
env = env,
135+
env = LinkedHashMap(env.toMap() + mapOf("GHWKT_GITHUB_CONTEXT_JSON" to "${'$'}{{ toJSON(github) }}")),
135136
condition = `if` ?: condition,
136137
continueOnError = continueOnError,
137138
timeoutMinutes = timeoutMinutes,

github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/yaml/ToYaml.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import io.github.typesafegithub.workflows.domain.Mode
77
import io.github.typesafegithub.workflows.domain.Permission
88
import io.github.typesafegithub.workflows.domain.RunnerType.UbuntuLatest
99
import io.github.typesafegithub.workflows.domain.Workflow
10+
import io.github.typesafegithub.workflows.domain.contexts.Contexts
11+
import io.github.typesafegithub.workflows.domain.contexts.GithubContext
1012
import io.github.typesafegithub.workflows.dsl.toBuilder
1113
import io.github.typesafegithub.workflows.internal.relativeToAbsolute
1214
import io.github.typesafegithub.workflows.shared.internal.findGitRoot
1315
import io.github.typesafegithub.workflows.yaml.Preamble.Just
1416
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalAfter
1517
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalBefore
18+
import kotlinx.serialization.json.Json
1619
import java.nio.file.Path
1720
import kotlin.io.path.absolute
1821
import kotlin.io.path.exists
@@ -82,7 +85,8 @@ public fun Workflow.writeToFile(
8285
.first { it.id == jobId }
8386
.steps
8487
.first { it.id == stepId } as KotlinLogicStep
85-
kotlinLogicStep.logic()
88+
val contexts = loadContextsFromEnvVars(getenv)
89+
kotlinLogicStep.logic(contexts)
8690
return
8791
}
8892

@@ -109,6 +113,16 @@ public fun Workflow.writeToFile(
109113
}
110114
}
111115

116+
private fun loadContextsFromEnvVars(getenv: (String) -> String?): Contexts {
117+
fun getEnvVarOrFail(varName: String): String = getenv(varName) ?: error("$varName should be set!")
118+
119+
val githubContextRaw = getEnvVarOrFail("GHWKT_GITHUB_CONTEXT_JSON")
120+
val githubContext = json.decodeFromString<GithubContext>(githubContextRaw)
121+
return Contexts(
122+
github = githubContext,
123+
)
124+
}
125+
112126
private fun commentify(preamble: String): String {
113127
if (preamble.isEmpty()) return ""
114128

@@ -242,3 +256,5 @@ private fun Workflow.toYamlInternal(jobsWithConsistencyCheck: List<Job<*>>): Map
242256
*_customArguments.toList().toTypedArray(),
243257
"jobs" to jobsWithConsistencyCheck.jobsToYaml(),
244258
)
259+
260+
private val json = Json { ignoreUnknownKeys = true }

0 commit comments

Comments
 (0)