Skip to content

Commit

Permalink
chore(dsl)!: write to file in workflow builder (#1429)
Browse files Browse the repository at this point in the history
Part of #1208.

Moving to a more declarative approach, so that there's no need to call the function explicitly - in practice, one always needs to call it, unless doing something awkward.
  • Loading branch information
krzema12 authored May 9, 2024
1 parent fc066b1 commit b84da76
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 367 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/end-to-end-tests.main.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import io.github.typesafegithub.workflows.dsl.JobBuilder
import io.github.typesafegithub.workflows.dsl.expressions.Contexts
import io.github.typesafegithub.workflows.dsl.expressions.expr
import io.github.typesafegithub.workflows.dsl.workflow
import io.github.typesafegithub.workflows.yaml.writeToFile
import io.github.typesafegithub.workflows.updates.reportAvailableUpdates
import java.time.Instant

Expand Down Expand Up @@ -251,6 +250,4 @@ workflow(
""".trimIndent(),
)
}
}.also { workflow ->
workflow.reportAvailableUpdates()
}.writeToFile()
}.reportAvailableUpdates()
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ build

# Created in unit tests - easier and more readable to ignore it rather than adjust the test.
/.github/workflows/.yaml
.github/workflows/some_workflow.yaml

# Action bindings are generated by CI each time, and locally we should regenerate it as often as possible.
/.github/workflows/generated
/.github/workflows/generated
6 changes: 2 additions & 4 deletions docs/user-guide/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ names with your own.
--8<-- "GettingStartedSnippets.kt:getting-started-2"
--8<-- "GettingStartedSnippets.kt:getting-started-3"
```
Explanation: first, we create a workflow with the DSL provided by this library. The reason it needs source
This way we create a workflow with the DSL provided by this library. The reason it needs source
file path is to be able to generate consistency checks, to ensure that both source and target files are in sync.
You'll see it in a moment in the generated file. What's written to the `workflow` variable is an object of type
`io.github.typesafegithub.workflows.domain.Workflow`, it's not a YAML yet. However, a call to `writeToFile()`
extension function does the final piece of job.
You'll see it in a moment in the generated file.
4. Generate the YAML by calling the above script:
```
.github/workflows/hello_world_workflow.main.kts
Expand Down
14 changes: 5 additions & 9 deletions github-workflows-kt/api/github-workflows-kt.api
Original file line number Diff line number Diff line change
Expand Up @@ -1899,9 +1899,10 @@ public final class io/github/typesafegithub/workflows/dsl/JobBuilder : io/github
}

public final class io/github/typesafegithub/workflows/dsl/WorkflowBuilder {
public fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/nio/file/Path;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/nio/file/Path;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/List;Ljava/util/Map;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lio/github/typesafegithub/workflows/domain/Workflow;
public final fun getGitRootDir ()Ljava/nio/file/Path;
public final fun job ([Lkotlin/Unit;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/RunnerType;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Concurrency;Lio/github/typesafegithub/workflows/domain/Container;Lio/github/typesafegithub/workflows/domain/Environment;Ljava/util/Map;Lio/github/typesafegithub/workflows/domain/JobOutputs;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/Job;
public final fun job ([Lkotlin/Unit;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/RunnerType;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Concurrency;Lio/github/typesafegithub/workflows/domain/Container;Lio/github/typesafegithub/workflows/domain/Environment;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/Job;
public static synthetic fun job$default (Lio/github/typesafegithub/workflows/dsl/WorkflowBuilder;[Lkotlin/Unit;Ljava/lang/String;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/RunnerType;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/Integer;Lio/github/typesafegithub/workflows/domain/Concurrency;Lio/github/typesafegithub/workflows/domain/Container;Lio/github/typesafegithub/workflows/domain/Environment;Ljava/util/Map;Lio/github/typesafegithub/workflows/domain/JobOutputs;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/Job;
Expand All @@ -1910,8 +1911,8 @@ public final class io/github/typesafegithub/workflows/dsl/WorkflowBuilder {

public final class io/github/typesafegithub/workflows/dsl/WorkflowBuilderKt {
public static final fun toBuilder (Lio/github/typesafegithub/workflows/domain/Workflow;)Lio/github/typesafegithub/workflows/dsl/WorkflowBuilder;
public static final fun workflow ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/Workflow;
public static synthetic fun workflow$default ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/Workflow;
public static final fun workflow ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ZLjava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;Lkotlin/jvm/functions/Function1;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lio/github/typesafegithub/workflows/domain/Workflow;
public static synthetic fun workflow$default ([Lkotlin/Unit;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/nio/file/Path;Ljava/lang/String;Lio/github/typesafegithub/workflows/domain/Concurrency;Ljava/lang/String;Ljava/util/Map;Lkotlin/jvm/functions/Function1;Ljava/util/Map;ZLjava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;Lkotlin/jvm/functions/Function1;Ljava/util/Map;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/github/typesafegithub/workflows/domain/Workflow;
}

public final class io/github/typesafegithub/workflows/dsl/expressions/Contexts : io/github/typesafegithub/workflows/dsl/expressions/contexts/FunctionsContext {
Expand Down Expand Up @@ -3147,11 +3148,6 @@ public final class io/github/typesafegithub/workflows/yaml/Preamble$WithOriginal
public fun <init> (Ljava/lang/String;)V
}

public final class io/github/typesafegithub/workflows/yaml/ToYamlKt {
public static final fun writeToFile (Lio/github/typesafegithub/workflows/domain/Workflow;ZLjava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun writeToFile$default (Lio/github/typesafegithub/workflows/domain/Workflow;ZLjava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public final class io/github/typesafegithub/workflows/yaml/TriggersToYamlKt {
public static final fun toMap (Lio/github/typesafegithub/workflows/domain/triggers/Trigger;)Ljava/util/Map;
public static final fun triggerName (Lio/github/typesafegithub/workflows/domain/triggers/Trigger;)Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import io.github.typesafegithub.workflows.domain.Shell
import io.github.typesafegithub.workflows.domain.actions.Action
import io.github.typesafegithub.workflows.domain.contexts.Contexts
import io.github.typesafegithub.workflows.dsl.expressions.expr
import io.github.typesafegithub.workflows.internal.relativeToAbsolute
import kotlinx.serialization.Contextual
import kotlin.io.path.name
import kotlin.io.path.invariantSeparatorsPathString

@Suppress("LongParameterList")
@GithubActionsDsl
Expand Down Expand Up @@ -133,14 +134,15 @@ public class JobBuilder<OUTPUT : JobOutputs>(
}

val id = "step-${job.steps.size}"
val sourceFilePath =
workflowBuilder.gitRootDir?.let {
sourceFile.relativeToAbsolute(it).invariantSeparatorsPathString
}
val newStep =
KotlinLogicStep(
id = id,
name = name,
// Because of the current architecture, it's hard to make this command work properly if the sourceFile
// isn't in .github/workflows directory. It's the most common use case, though, so for now this
// simplified implementation is used.
command = "GHWKT_RUN_STEP='${this.id}:$id' '.github/workflows/${sourceFile.name}'",
command = "GHWKT_RUN_STEP='${this.id}:$id' '$sourceFilePath'",
logic = logic,
env = env + mapOf("GHWKT_GITHUB_CONTEXT_JSON" to "${'$'}{{ toJSON(github) }}"),
condition =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ import io.github.typesafegithub.workflows.domain.Permission
import io.github.typesafegithub.workflows.domain.RunnerType
import io.github.typesafegithub.workflows.domain.Workflow
import io.github.typesafegithub.workflows.domain.triggers.Trigger
import io.github.typesafegithub.workflows.shared.internal.findGitRoot
import io.github.typesafegithub.workflows.yaml.Preamble
import io.github.typesafegithub.workflows.yaml.writeToFile
import kotlinx.serialization.Contextual
import java.nio.file.Path
import kotlin.io.path.absolute

@GithubActionsDsl
@Suppress("LongParameterList", "FunctionParameterNaming", "ConstructorParameterNaming")
Expand All @@ -22,6 +26,7 @@ public class WorkflowBuilder(
sourceFile: Path?,
targetFileName: String?,
concurrency: Concurrency? = null,
public val gitRootDir: Path? = null,
yamlConsistencyJobCondition: String? = null,
yamlConsistencyJobEnv: Map<String, String> = mapOf(),
yamlConsistencyJobAdditionalSteps: (JobBuilder<JobOutputs.EMPTY>.() -> Unit)? = null,
Expand Down Expand Up @@ -171,6 +176,10 @@ public fun workflow(
yamlConsistencyJobEnv: Map<String, String> = mapOf(),
yamlConsistencyJobAdditionalSteps: (JobBuilder<JobOutputs.EMPTY>.() -> Unit)? = null,
permissions: Map<Permission, Mode>? = null,
addConsistencyCheck: Boolean = sourceFile != null,
gitRootDir: Path? = sourceFile?.absolute()?.findGitRoot(),
preamble: Preamble? = null,
getenv: (String) -> String? = { System.getenv(it) },
_customArguments: Map<String, @Contextual Any> = mapOf(),
block: WorkflowBuilder.() -> Unit,
): Workflow {
Expand All @@ -187,6 +196,7 @@ public fun workflow(
targetFileName = targetFileName,
permissions = permissions,
concurrency = concurrency,
gitRootDir = gitRootDir,
yamlConsistencyJobCondition = yamlConsistencyJobCondition,
yamlConsistencyJobEnv = yamlConsistencyJobEnv,
yamlConsistencyJobAdditionalSteps = yamlConsistencyJobAdditionalSteps,
Expand All @@ -200,6 +210,14 @@ public fun workflow(
workflowBuilder.workflow.jobs.requireUniqueJobIds()

return workflowBuilder.build()
.also {
it.writeToFile(
addConsistencyCheck = addConsistencyCheck,
gitRootDir = gitRootDir,
preamble = preamble,
getenv = getenv,
)
}
}

private fun List<Job<*>>.requireUniqueJobIds() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ import io.github.typesafegithub.workflows.domain.contexts.Contexts
import io.github.typesafegithub.workflows.domain.contexts.GithubContext
import io.github.typesafegithub.workflows.dsl.toBuilder
import io.github.typesafegithub.workflows.internal.relativeToAbsolute
import io.github.typesafegithub.workflows.shared.internal.findGitRoot
import io.github.typesafegithub.workflows.yaml.Preamble.Just
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalAfter
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalBefore
import kotlinx.serialization.json.Json
import java.nio.file.Path
import kotlin.io.path.absolute
import kotlin.io.path.invariantSeparatorsPathString

/**
Expand All @@ -34,11 +32,11 @@ import kotlin.io.path.invariantSeparatorsPathString
* @param preamble Allows customizing the comment at the beginning of the generated YAML by either passing an extra
* string, or replacing the whole preamble.
*/
public fun Workflow.writeToFile(
addConsistencyCheck: Boolean = sourceFile != null,
gitRootDir: Path? = sourceFile?.absolute()?.findGitRoot(),
preamble: Preamble? = null,
getenv: (String) -> String? = { System.getenv(it) },
internal fun Workflow.writeToFile(
addConsistencyCheck: Boolean,
gitRootDir: Path?,
preamble: Preamble?,
getenv: (String) -> String?,
) {
val runStepEnvVar = getenv("GHWKT_RUN_STEP")

Expand Down
Loading

0 comments on commit b84da76

Please sign in to comment.