Skip to content

Commit

Permalink
Add continous build
Browse files Browse the repository at this point in the history
  • Loading branch information
Vampire committed Aug 11, 2024
1 parent 16eca47 commit 3d9d7bd
Show file tree
Hide file tree
Showing 6 changed files with 644 additions and 2 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
== The YAML workflow files vs. the `*.main.kts` files

The YAML workflow files are generated from the `*.main.kts` files.

These use the https://github.com/typesafegithub/github-workflows-kt[github-workflows-kt]
Kotlin DSL library to conveniently and type-safely write GitHub Action workflow files.

As there is no official built-in support in GitHub Actions yet until
https://github.com/orgs/community/discussions/15904 is considered, the YAML files
need to be generated manually.

There is a safeguard check in all the generated files that this is not forgotten.
Running a workflow where the according `*.main.kts` produces a different output will
fail the execution. Additionally, the workflow that runs for pushes and pull requests
checks the consistency of all the YAML files as not all might be run for pull requests.



== Ways to generate the YAML workflow files

There are multiple ways to generate the YAML files and all of them are fine,
but be aware of the last one of the caveats below if you are not using the Gradle method:

* If you are in a `sh` derivate like e.g. `bash` and Kotlin is installed and
available in the `PATH`, you can just call the `*.main.kts` script like any
other shell script:
+
[source,bash]
----
$ ./release.main.kts
----

* If Kotlin is installed somewhere you can call it with the `*.main.kts` script
as argument:
+
[source,bash]
----
$ path/to/kotlin release.main.kts
----

* From the IDE you can create a run configuration that executes the `*.main.kts` script.



== Caveat

There is currently one known caveats with the approach we follow.

* https://youtrack.jetbrains.com/issue/KTIJ-16532
+
If you navigate to a file in the dependencies, only a decompiled file is opened,
even though the source JAR would be available. Also the quick documentation is missing.
+
This can easily by mitigated by attaching the library to the normal project
dependencies while having the need to navigate the source files or while editing them,
which makes them properly viewable and documentation displayable in the editor.
280 changes: 280 additions & 0 deletions .github/workflows/build.main.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
#!/usr/bin/env kotlin

@file:Repository("https://repo.maven.apache.org/maven2/")
@file:DependsOn("io.github.typesafegithub:github-workflows-kt:2.3.0")

@file:Repository("https://bindings.krzeminski.it/")
@file:DependsOn("actions:checkout:v4")
@file:DependsOn("actions:setup-java:v4")
@file:DependsOn("DamianReeves:write-file-action:v1.3")
@file:DependsOn("actions:upload-artifact:v4")
@file:DependsOn("actions:upload-artifact__merge:v4")

import io.github.typesafegithub.workflows.actions.actions.Checkout
import io.github.typesafegithub.workflows.actions.actions.SetupJava
import io.github.typesafegithub.workflows.actions.actions.SetupJava.Distribution.Temurin
import io.github.typesafegithub.workflows.actions.actions.UploadArtifact
import io.github.typesafegithub.workflows.actions.actions.UploadArtifact.BehaviorIfNoFilesFound
import io.github.typesafegithub.workflows.actions.actions.UploadArtifact.BehaviorIfNoFilesFound.Error
import io.github.typesafegithub.workflows.actions.actions.UploadArtifact.BehaviorIfNoFilesFound.Ignore
import io.github.typesafegithub.workflows.actions.actions.UploadArtifact.CompressionLevel.NoCompression
import io.github.typesafegithub.workflows.actions.damianreeves.WriteFileAction
import io.github.typesafegithub.workflows.domain.AbstractResult.Status.Success
import io.github.typesafegithub.workflows.domain.RunnerType
import io.github.typesafegithub.workflows.domain.Shell.Bash
import io.github.typesafegithub.workflows.domain.triggers.PullRequest
import io.github.typesafegithub.workflows.domain.triggers.Push
import io.github.typesafegithub.workflows.dsl.expressions.Contexts.always
import io.github.typesafegithub.workflows.dsl.expressions.Contexts.runner
import io.github.typesafegithub.workflows.dsl.expressions.expr
import io.github.typesafegithub.workflows.dsl.workflow
import io.github.typesafegithub.workflows.yaml.ConsistencyCheckJobConfig.Disabled

workflow(
name = "Build",
on = listOf(
Push(),
PullRequest()
),
sourceFile = __FILE__,
//TODO
consistencyCheckJobConfig = Disabled
) {
//TODO
//job(
// id = "check_all_workflow_yaml_consistency",
// name = "Check all Workflow YAML consistency",
// runsOn = UbuntuLatest
//) {
// uses(
// name = "Checkout",
// action = Checkout()
// )
// run(
// name = "Regenerate all workflow YAMLs and check for modifications",
// command = "find .github/workflows -mindepth 1 -maxdepth 1 -name '*.main.kts' | xargs -ri sh -c '{} && git diff --exit-code'"
// )
//}

job(
id = "build",
name = "Build on ${expr("matrix.os")}",
runsOn = RunnerType.Custom(expr("matrix.os")),
_customArguments = mapOf(
"strategy" to mapOf(
"fail-fast" to false,
"matrix" to mapOf(
"os" to listOf(
"ubuntu-latest",
"windows-latest",
"macos-latest"
)
)
)
)
) {
run(
name = "Install InnoSetup on Linux",
command = """
sudo dpkg --add-architecture i386
sudo wget -nc -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key
sudo wget -NP /etc/apt/sources.list.d/ "https://dl.winehq.org/wine-builds/ubuntu/dists/${'$'}(lsb_release -c | grep -o '\w*${'$'}')/winehq-${'$'}(lsb_release -c | grep -o '\w*${'$'}').sources"
sudo apt update
sudo apt install --yes --no-install-recommends winehq-stable
winecfg /v win10
wget https://files.jrsoftware.org/is/6/innosetup-6.3.3.exe
Xvfb :0 -screen 0 1024x768x16 &
export DISPLAY=:0.0
wine innosetup-6.3.3.exe /SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
""".trimIndent(),
condition = "${runner.os} == 'Linux'",
shell = Bash
)

run(
name = "Install InnoSetup on macOS",
command = """
brew install wine-stable
wget https://files.jrsoftware.org/is/6/innosetup-6.3.3.exe
wine innosetup-6.3.3.exe /SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART
""".trimIndent(),
condition = "${runner.os} == 'macOS'",
shell = Bash
)

run(
name = "Configure Git",
command = "git config --global core.autocrlf input"
)

uses(
name = "Checkout",
action = Checkout()
)

uses(
name = "Setup Java 11",
action = SetupJava(
javaVersion = "11",
distribution = Temurin
)
)

uses(
name = "Configure Build Properties for Windows",
action = WriteFileAction(
path = "build.properties",
contents = """
innosetup.compiler.executable = C:/Program Files (x86)/Inno Setup 6/ISCC.exe
""".trimIndent()
),
condition = "${runner.os} == 'Windows'"
)

uses(
name = "Configure Build Properties for Linux",
action = WriteFileAction(
path = "build.properties",
contents = """
wine.executable = wine
winepath.executable = winepath
innosetup.compiler.executable = /Users/runner/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe
innosetup.via.wine = true
""".trimIndent()
),
condition = "${runner.os} == 'macOS'"
)

val build = run(
name = "Build",
command = "ant -keep-going dist"
)

val allPossibleArtifacts = listOf(
Artifact(
name = "Manual in A4 Paper size",
path = "dist/jedit*manual-a4.pdf"
),
Artifact(
name = "Manual in Letter Paper size",
path = "dist/jedit*manual-letter.pdf"
),
Artifact(
name = "Source Package",
path = "dist/jedit*source.tar.bz2"
),
Artifact(
name = "Java based Installer",
path = "dist/jedit*install.jar"
),
Artifact(
name = "Slackware Installer",
path = "dist/jedit-*-noarch-1sao.tgz"
),
Artifact(
name = "Debian Installer",
path = "dist/jedit_*_all.deb"
),
Artifact(
name = "Windows Installer",
path = "dist/jedit*install.exe"
),
Artifact(
name = "macOS Installer",
path = "dist/jedit*install.dmg",
condition = "${runner.os} == 'macOS'"
),
Artifact(
name = "macOS Intermediate Result",
path = "dist/jedit*-dist-mac-finish.tar.bz2",
condition = "${runner.os} != 'macOS'"
),
Artifact(
name = "Debian Repository Packages File",
path = "dist/Packages",
ifNoFilesFound = Ignore
),
Artifact(
name = "Debian Repository Packages File (gz)",
path = "dist/Packages.gz",
ifNoFilesFound = Ignore
),
Artifact(
name = "Debian Repository Packages File (bz2)",
path = "dist/Packages.bz2",
ifNoFilesFound = Ignore
),
Artifact(
name = "Debian Repository Release File",
path = "dist/Release",
ifNoFilesFound = Ignore
),
Artifact(
name = "Debian Repository Release File Signature",
path = "dist/Release.gpg",
ifNoFilesFound = Ignore
)
)

val buildSuccessful = """
(${always()})
&& (${build.outcome eq Success})
""".trimIndent()

// Upload all result files from macOS build that can build all artifacts as one archive
uses(
name = "Upload All Result Files",
action = UploadArtifact(
name = "All Artifacts",
path = allPossibleArtifacts.map { it.path },
ifNoFilesFound = Error,
compressionLevel = NoCompression
),
condition = "($buildSuccessful) && (${runner.os} == 'macOS')"
)

// upload each artifact as single archive for individual download
// and also to verify it was built, hence not restricted to OS
allPossibleArtifacts.forEach { (name, path, ifNoFilesFound, condition) ->
uses(
name = "Upload $name",
action = UploadArtifact(
name = name,
path = listOf(path),
ifNoFilesFound = ifNoFilesFound,
compressionLevel = NoCompression,
overwrite = true
),
condition = condition?.let { "($buildSuccessful) && ($it)" } ?: buildSuccessful
)
}

val uploadAllUnexpectedResultFiles = uses(
name = "Upload All Unexpected Result Files",
action = UploadArtifact(
name = "Unexpected Artifacts (${expr { runner.os }})",
path = listOf("dist") + allPossibleArtifacts.map { "!${it.path}" },
ifNoFilesFound = Ignore,
compressionLevel = NoCompression
),
condition = buildSuccessful
)

run(
name = "Verify No Unexpected Result Files",
command = "[ '${expr { uploadAllUnexpectedResultFiles.outputs.artifactId }}' == '' ]",
condition = """
(${always()})
&& (${uploadAllUnexpectedResultFiles.outcome eq Success})
""".trimIndent(),
shell = Bash
)
}
}

data class Artifact(
val name: String,
val path: String,
val ifNoFilesFound: BehaviorIfNoFilesFound = Error,
val condition: String? = null
)
Loading

0 comments on commit 3d9d7bd

Please sign in to comment.