Skip to content

Commit 7f0e076

Browse files
authored
feat(dsl): allow writing workflow to string (#1486)
Closes #1468. It was possible in 1.x, and this possibility was removed because I assumed no one needs it. It turns out that some users prefer writing the YAML themselves. This simple backward-compatible change gives more freedom to the users of the lib.
1 parent 97dace4 commit 7f0e076

File tree

4 files changed

+81
-16
lines changed

4 files changed

+81
-16
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,11 @@ public final class io/github/typesafegithub/workflows/yaml/Preamble$WithOriginal
31743174
public fun <init> (Ljava/lang/String;)V
31753175
}
31763176

3177+
public final class io/github/typesafegithub/workflows/yaml/ToYamlKt {
3178+
public static final fun generateYaml (Lio/github/typesafegithub/workflows/domain/Workflow;Ljava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;)Ljava/lang/String;
3179+
public static synthetic fun generateYaml$default (Lio/github/typesafegithub/workflows/domain/Workflow;Ljava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;ILjava/lang/Object;)Ljava/lang/String;
3180+
}
3181+
31773182
public final class io/github/typesafegithub/workflows/yaml/TriggersToYamlKt {
31783183
public static final fun toMap (Lio/github/typesafegithub/workflows/domain/triggers/Trigger;)Ljava/util/Map;
31793184
public static final fun triggerName (Lio/github/typesafegithub/workflows/domain/triggers/Trigger;)Ljava/lang/String;

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ public fun Workflow.toBuilder(): WorkflowBuilder =
163163
_customArguments = _customArguments,
164164
)
165165

166+
/**
167+
* A DSL function that models the top-level parts of the GitHub Actions workflow.
168+
*
169+
* @param targetFileName Name of the produced YAML file inside the `.github/workflows` directory. If set to `null`,
170+
* writing to file is disabled.
171+
*/
166172
@Suppress("LongParameterList", "FunctionParameterNaming")
167173
public fun workflow(
168174
@Suppress("UNUSED_PARAMETER")
@@ -215,11 +221,13 @@ public fun workflow(
215221

216222
return workflowBuilder.build()
217223
.also {
218-
it.writeToFile(
219-
gitRootDir = gitRootDir,
220-
preamble = preamble,
221-
getenv = getenv,
222-
)
224+
if (targetFileName != null) {
225+
it.writeToFile(
226+
gitRootDir = gitRootDir,
227+
preamble = preamble,
228+
getenv = getenv,
229+
)
230+
}
223231
}
224232
}
225233

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import io.github.typesafegithub.workflows.domain.contexts.Contexts
1111
import io.github.typesafegithub.workflows.domain.contexts.GithubContext
1212
import io.github.typesafegithub.workflows.dsl.toBuilder
1313
import io.github.typesafegithub.workflows.internal.relativeToAbsolute
14+
import io.github.typesafegithub.workflows.shared.internal.findGitRoot
1415
import io.github.typesafegithub.workflows.yaml.Preamble.Just
1516
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalAfter
1617
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalBefore
1718
import kotlinx.serialization.json.Json
1819
import java.nio.file.Path
20+
import kotlin.io.path.absolute
1921
import kotlin.io.path.invariantSeparatorsPathString
2022

2123
/**
@@ -52,10 +54,6 @@ internal fun Workflow.writeToFile(
5254
"gitRootDir must be specified explicitly when sourceFile is null"
5355
}
5456

55-
checkNotNull(this.targetFileName) {
56-
"targetFileName must not be null"
57-
}
58-
5957
val yaml =
6058
generateYaml(
6159
gitRootDir = gitRootDir,
@@ -86,26 +84,29 @@ private fun commentify(preamble: String): String {
8684
.joinToString("\n", postfix = "\n\n") { "# $it".trimEnd() }
8785
}
8886

87+
/**
88+
* Return a YAML for a workflow passed as the receiver.
89+
*/
8990
@Suppress("LongMethod")
90-
private fun Workflow.generateYaml(
91-
gitRootDir: Path?,
92-
preamble: Preamble?,
91+
public fun Workflow.generateYaml(
92+
gitRootDir: Path? = sourceFile?.toPath()?.absolute()?.findGitRoot(),
93+
preamble: Preamble? = null,
9394
): String {
9495
val sourceFilePath =
9596
gitRootDir?.let {
9697
sourceFile?.toPath()?.relativeToAbsolute(gitRootDir)?.invariantSeparatorsPathString
9798
}
9899

100+
require(!(consistencyCheckJobConfig is ConsistencyCheckJobConfig.Configuration && targetFileName == null)) {
101+
"consistency check requires a targetFileName"
102+
}
103+
99104
val jobsWithConsistencyCheck =
100105
if (consistencyCheckJobConfig is ConsistencyCheckJobConfig.Configuration) {
101106
check(gitRootDir != null && sourceFile != null) {
102107
"consistency check requires a valid sourceFile and Git root directory"
103108
}
104109

105-
checkNotNull(targetFileName) {
106-
"consistency check requires a targetFileName"
107-
}
108-
109110
val targetFilePath =
110111
gitRootDir.resolve(".github").resolve("workflows").resolve(targetFileName)
111112
.relativeToAbsolute(gitRootDir).invariantSeparatorsPathString

github-workflows-kt/src/test/kotlin/io/github/typesafegithub/workflows/IntegrationTest.kt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.github.typesafegithub.workflows.yaml.DEFAULT_CONSISTENCY_CHECK_JOB_CON
1414
import io.github.typesafegithub.workflows.yaml.Preamble.Just
1515
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalAfter
1616
import io.github.typesafegithub.workflows.yaml.Preamble.WithOriginalBefore
17+
import io.github.typesafegithub.workflows.yaml.generateYaml
1718
import io.kotest.assertions.throwables.shouldThrow
1819
import io.kotest.core.spec.style.FunSpec
1920
import io.kotest.engine.spec.tempdir
@@ -30,6 +31,10 @@ class IntegrationTest : FunSpec({
3031
val sourceTempFile = gitRootDir.resolve(".github/workflows/some_workflow.main.kts").toFile()
3132
val targetTempFile = gitRootDir.resolve(".github/workflows/some_workflow.yaml").toFile()
3233

34+
afterTest {
35+
targetTempFile.delete()
36+
}
37+
3338
test("'hello world' workflow") {
3439
// when
3540
workflow(
@@ -770,4 +775,50 @@ class IntegrationTest : FunSpec({
770775
it.message shouldBe "sourceFile needs to be set when using Kotlin-based 'run' block!"
771776
}
772777
}
778+
779+
test("return workflow as string and do not write to file") {
780+
// given
781+
val workflow =
782+
workflow(
783+
name = "Test workflow",
784+
on = listOf(Push()),
785+
sourceFile = sourceTempFile,
786+
targetFileName = null,
787+
consistencyCheckJobConfig = Disabled,
788+
) {
789+
job(
790+
id = "test_job",
791+
runsOn = RunnerType.UbuntuLatest,
792+
) {
793+
uses(
794+
name = "Check out",
795+
action = CheckoutV4(),
796+
)
797+
}
798+
}
799+
800+
// when
801+
val workflowYaml = workflow.generateYaml()
802+
803+
// then
804+
workflowYaml shouldBe
805+
"""
806+
# This file was generated using Kotlin DSL (.github/workflows/some_workflow.main.kts).
807+
# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file.
808+
# Generated with https://github.com/typesafegithub/github-workflows-kt
809+
810+
name: 'Test workflow'
811+
on:
812+
push: {}
813+
jobs:
814+
test_job:
815+
runs-on: 'ubuntu-latest'
816+
steps:
817+
- id: 'step-0'
818+
name: 'Check out'
819+
uses: 'actions/checkout@v4'
820+
821+
""".trimIndent()
822+
targetTempFile.exists() shouldBe false
823+
}
773824
})

0 commit comments

Comments
 (0)