Skip to content

Commit

Permalink
feat(dsl): allow writing workflow to string (#1486)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
krzema12 committed Jun 9, 2024
1 parent 97dace4 commit 7f0e076
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 16 deletions.
5 changes: 5 additions & 0 deletions github-workflows-kt/api/github-workflows-kt.api
Original file line number Diff line number Diff line change
Expand Up @@ -3174,6 +3174,11 @@ 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 generateYaml (Lio/github/typesafegithub/workflows/domain/Workflow;Ljava/nio/file/Path;Lio/github/typesafegithub/workflows/yaml/Preamble;)Ljava/lang/String;
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;
}

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 @@ -163,6 +163,12 @@ public fun Workflow.toBuilder(): WorkflowBuilder =
_customArguments = _customArguments,
)

/**
* A DSL function that models the top-level parts of the GitHub Actions workflow.
*
* @param targetFileName Name of the produced YAML file inside the `.github/workflows` directory. If set to `null`,
* writing to file is disabled.
*/
@Suppress("LongParameterList", "FunctionParameterNaming")
public fun workflow(
@Suppress("UNUSED_PARAMETER")
Expand Down Expand Up @@ -215,11 +221,13 @@ public fun workflow(

return workflowBuilder.build()
.also {
it.writeToFile(
gitRootDir = gitRootDir,
preamble = preamble,
getenv = getenv,
)
if (targetFileName != null) {
it.writeToFile(
gitRootDir = gitRootDir,
preamble = preamble,
getenv = getenv,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ 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 Down Expand Up @@ -52,10 +54,6 @@ internal fun Workflow.writeToFile(
"gitRootDir must be specified explicitly when sourceFile is null"
}

checkNotNull(this.targetFileName) {
"targetFileName must not be null"
}

val yaml =
generateYaml(
gitRootDir = gitRootDir,
Expand Down Expand Up @@ -86,26 +84,29 @@ private fun commentify(preamble: String): String {
.joinToString("\n", postfix = "\n\n") { "# $it".trimEnd() }
}

/**
* Return a YAML for a workflow passed as the receiver.
*/
@Suppress("LongMethod")
private fun Workflow.generateYaml(
gitRootDir: Path?,
preamble: Preamble?,
public fun Workflow.generateYaml(
gitRootDir: Path? = sourceFile?.toPath()?.absolute()?.findGitRoot(),
preamble: Preamble? = null,
): String {
val sourceFilePath =
gitRootDir?.let {
sourceFile?.toPath()?.relativeToAbsolute(gitRootDir)?.invariantSeparatorsPathString
}

require(!(consistencyCheckJobConfig is ConsistencyCheckJobConfig.Configuration && targetFileName == null)) {
"consistency check requires a targetFileName"
}

val jobsWithConsistencyCheck =
if (consistencyCheckJobConfig is ConsistencyCheckJobConfig.Configuration) {
check(gitRootDir != null && sourceFile != null) {
"consistency check requires a valid sourceFile and Git root directory"
}

checkNotNull(targetFileName) {
"consistency check requires a targetFileName"
}

val targetFilePath =
gitRootDir.resolve(".github").resolve("workflows").resolve(targetFileName)
.relativeToAbsolute(gitRootDir).invariantSeparatorsPathString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.github.typesafegithub.workflows.yaml.DEFAULT_CONSISTENCY_CHECK_JOB_CON
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 io.github.typesafegithub.workflows.yaml.generateYaml
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.engine.spec.tempdir
Expand All @@ -30,6 +31,10 @@ class IntegrationTest : FunSpec({
val sourceTempFile = gitRootDir.resolve(".github/workflows/some_workflow.main.kts").toFile()
val targetTempFile = gitRootDir.resolve(".github/workflows/some_workflow.yaml").toFile()

afterTest {
targetTempFile.delete()
}

test("'hello world' workflow") {
// when
workflow(
Expand Down Expand Up @@ -770,4 +775,50 @@ class IntegrationTest : FunSpec({
it.message shouldBe "sourceFile needs to be set when using Kotlin-based 'run' block!"
}
}

test("return workflow as string and do not write to file") {
// given
val workflow =
workflow(
name = "Test workflow",
on = listOf(Push()),
sourceFile = sourceTempFile,
targetFileName = null,
consistencyCheckJobConfig = Disabled,
) {
job(
id = "test_job",
runsOn = RunnerType.UbuntuLatest,
) {
uses(
name = "Check out",
action = CheckoutV4(),
)
}
}

// when
val workflowYaml = workflow.generateYaml()

// then
workflowYaml shouldBe
"""
# This file was generated using Kotlin DSL (.github/workflows/some_workflow.main.kts).
# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file.
# Generated with https://github.com/typesafegithub/github-workflows-kt
name: 'Test workflow'
on:
push: {}
jobs:
test_job:
runs-on: 'ubuntu-latest'
steps:
- id: 'step-0'
name: 'Check out'
uses: 'actions/checkout@v4'
""".trimIndent()
targetTempFile.exists() shouldBe false
}
})

0 comments on commit 7f0e076

Please sign in to comment.