GitHub Actions:YAML 编程荒原中的新希望
程序员最大的超能力在于 她 能够 自动化几乎所有事情。 这就是 GitHub Actions 的优势所在…… 前提是 你能自信地 用 YAML编写一个 GitHub 工作流 来解决 你的特定问题。 这还只是个 假设 。但即使你不能,也还有 希望 。
让我向你介绍一个由 Piotr Krzemiński 发起的开源项目,过去几个月我为该项目做出了很大贡献👨🏻💻
使用 Kotlin 编写 GitHub Actions 工作流。你再也不需要用 YAML 了!
github-workflows-kt是一个在 类型安全脚本中生成 GitHub Actions 工作流 YAML 文件 的 工具 ,可帮助您使用 Kotlin 愉快地为您的 GitHub 项目构建 稳健 的 工作流,而不会出现 错误 。
您不会再回到 YAML!
💡 想法
我们经常被 YAML 配置所包围。它是一种功能强大的格式,提供了用于定义分层数据的简单语法,但有时它会被(滥用?)用于配置复杂的场景,从而导致文件复杂,难以编写和维护。
我们当中谁没有不小心使用了错误的缩进,错过了提取可重用代码的机会,或者被模糊的类型弄糊涂过?在这些情况下,通用编程语言的强大功能就会派上用场。
我们正在开发 github-workflows-kt 来解决这些问题和其他问题,以便您可以放心地创建 GitHub 工作流。
✨ 好处
没有缩进混淆 ——Kotlin 的语法不依赖于它
立即 ……
什么意思 github-actions-kotlin-dsl?
github-actions-kotlin-dsl(*) 是一个库,允许您以类型安全的方式为 Kotlin Actions 生成 GitHub 工作流。
(*) 我知道这有点拗口。我个人称之为 github-actions.kts
1) 在免费且出色的 IntelliJ IDEA 社区版中编辑脚本 2) 将脚本放入文件夹中 .github/workflows,使其可执行 3) 安装 Kotlin 4) github-actions-kotlin-dsl是用于构建 GitHub Workflow 对象的库 5) 最后,调用 workflow.writeToFile() 6) 生成 .github/workflows/$NAME$.yaml可在 GitHub Actions 上运行的脚本。
您可以看到蓝色下划线表示 YAML 工作流的主要组件具有直接的 Kotlin 等效项: workflow() Push() job() uses() run() GithubActionNameVxxx()
要实际运行您的第一个 Kotlin 工作流, 请阅读友好的文档
此时,您可能会问自己:
等等,但是为什么🤔?
GitHub Actions 是一项很棒的服务,但是......
程序员的主要超能力是 她 能够 自动化几乎所有事情。
因为这正是 GitHub Actions 的用途,所以一切都很好,对吧?
不幸的是, 大多数人都很难编写 GitHub 工作流程来解决他们的特定问题 :这是因为 YAML 是一种糟糕的编程语言 - 见下文。
因此,我们转而采用 复制/粘贴编程 ,试图找到已经花时间编写工作流程来解决与我们类似的问题的人。
别误会,复制/粘贴编程总比没有好,我已经为 Java/Kotlin 开发人员编写了一份指南,帮助他们快速启动并运行 CI
但如果我们不能自动化解决特定问题,我们就会错失良机。
那么问题是什么?
Github 的 YAML 是一种糟糕的编程语言
普通的 YAML 开发人员试图完成任务,但每次迭代之间都会浪费十分钟或更长时间。
一般来说,YAML 只是编写 JSON 的另一种方式。
有一系列不同的问题...
但 GitHub 按照Duck Typing 的原理,把 YAML 扩展成了我们应该认可的编程语言 。
* 🐥 GitHub YAML 作为编程语言:🐥 *
它允许编写任意脚本
它在 Azure 上的任意 VM 上运行
...具有任意数量的作业和命令
...用任意语言编写的大量插件,可以以各种方式进行配置
...带有变量和秘密
...使用 for 循环 - 又称策略矩阵
...使用布尔逻辑 - 仅当前一个作业成功时才运行此作业,仅在出现错误时运行此操作
...使用强大的 GitHib 表达式 - 又称为 eval函数
...
如果它走路像鸭子、叫声也像鸭子,那它一定是只鸭子。
这里的问题是 YAML 从来没有为此设计过
因此,IDE 的支持相当差。他们确实会尽力提供帮助,但远不如真正的编程语言。YAML 看起来比 JSON 更花哨,是因为它的规则不那么简单,但这意味着你更容易出错。
最重要的是:
GitHub Action 的编辑-编译-运行反馈循环非常慢
您在上图中看不到的是,GitHub Actions YAML 开发人员可能在脚本的每次迭代中浪费 10 分钟或更长时间!
那么,有没有办法走出 YAML 荒地呢?
类型安全的工作流
在 YAML 中,不正确的语法看起来很像正确的语法。
on:
cron: '7 42 * * 7'
schedule: '7 42 * * 7'
cron:
schedule: '7 42 * * 7'
schedule:
cron: '7 42 * * 7'
schedule:
- cron: '7 42 * * 7'
Enter fullscreen mode
Exit fullscreen mode
哪种语法是正确的?
这次没有争论了。类型系统的存在本身就让各种小错误消失了!
该库还保证其生成的所有内容都是有效的 YAML。无需再等待 CI 生成 MalformedYamlError...
此外,还有一些运行时检查,它会立即且快速地失败,而不是稍后缓慢地失败。
name: Hello : World!
on :
pr :
schedule :
- cron : ' 7 42 * * 7'
jobs :
" git checkout" :
runs-on : " ubuntu_latest"
steps :
- id : step-0
name: First : git checkout
uses : actions/checkout@v3
Enter fullscreen mode
Exit fullscreen mode
你能找到上述工作流程中的 7 个错误吗?
让我们看一下 Kotlin 的对应代码
val workflow = workflow (
name = "Hello: World" , // 1. runtime error: semicolon not allowed
on = listOf (
Schedule ( listOf (
// 2. named arguments 07:42 instead of 42:07 in the YAML
// 3. runtime error: Field 'dayWeek' outside of range 0..6
Cron ( minute = "42" , hour = "7" , dayWeek = "7" ))
),
PR (), // 4. compile error: should be PullRequest()
),
sourceFile = __FILE__ . toPath (),
) {
job (
id = "git checkout" , // 5. runtime error: space not allowed in a job id
runsOn = ubuntu_latest // 6. compile error: should be UbuntuLatest
) {
// 7. runtime error: semicolon not allowed here
uses ( name = "First: Check out" , action = CheckoutV3 ())
}
}
Enter fullscreen mode
Exit fullscreen mode
只需编译和运行脚本,我们就可以避免大量小错误 ,这些错误会浪费我们在 CI 上的每 10 分钟时间。
类型安全操作
看看这个动作是如何配置的:
steps :
- id : step-0
name : git check out
uses : actions/checkout@v4
with :
branch : main
fetch-depth : 0
Enter fullscreen mode
Exit fullscreen mode
这里有三个问题:
branch看起来像一个有效参数,但实际上不是
我不知道魔法值是什么 fetch-depth意思
v4 尚不存在
我们来看看 Kotlin 版本:
在这里我们清楚地看到这 branch是错误的,自动完成功能告诉我们 ref使用
F1: Documentation允许我们查看文档,并且特殊值有一个名称。
CheckoutV4甚至无法编译
在我写下这些文字的时候,我们已经 支持 89 个动作包装器
类型安全表达式
GitHub Actions 还具有强大的表达式语法。
我想你现在明白了:我们也为它们提供了一种类型安全的替代方案:
更多信息请阅读: https://krzema12.github.io/github-actions-kotlin-dsl/user-guide/type-safe-expressions/
自动迁移您现有的工作流程
现在我知道你在想什么了:
这太酷了,我刚开始的时候就希望有这个功能。 但现在我有一个可以运行的 YAML 工作流, 我不想从头开始。
我理解你的想法。 我也有同样的担忧。
然后一个邪恶的想法在我脑海里诞生了:
好的,所以我们可以编写一个 Kotlin 脚本来生成它的 YAML 版本。 但是,我们能否利用现有的 YAML 来生成一个可以自行生成的 Kotlin 脚本呢?这有点像孩子生下父母一样。
事实证明这是可行的,经过一番深入的思考, 脚本生成器诞生了 。它允许您自动迁移到 Kotlin。
你可以运行如下命令:
$ ./gradlew :script-generator:run --args /path/to/.github/workflows/build.yaml
Kotlin script written to build.main.kts
Run it with: ./build.main.kts
The resulting YAML file with be available at build.yaml
Enter fullscreen mode
Exit fullscreen mode
然后,您可以通过使用https://yamldiff.com/ 进行语义差异来确保新的 YAML 与旧的 YAML 等效
我不会详细介绍: 请阅读友好的文档
幕后:包装器生成器
当我发现这个项目时,图书馆支持的活动可能有十几个。
我主要关心的是:如何扩大规模?
GitHub Actions 有几十个,而且它们总是在发布新版本,添加或弃用参数。
答案:维护者 Piotr Krzemiński 和我引入了 动作包装器的自动生成 。
创建这个包装器生成器需要做很多工作,但它是值得的:
在我写下这些文字的时候,我们已经 支持 89 个动作包装器
幕后:GitHub Actions
另一件让我们能够在有限时间内应对挑战的事情是: GitHub Actions 本身 。
我们是我们库的首批用户,并利用了 GitHub Actions 的强大功能:
检查是否需要更新一些现有的包装器(例如新参数)。
检查现有包装器(V2 到 V3)是否有新的主要版本可用。
自动发布我们的库。
作为我们 PR 上的 CI
对于那些有动力的人来说,我们的行动可以在以下网址找到: https://github.com/krzema12/github-actions-kotlin-dsl/tree/main/.github/workflows
这确实让我深有体会:如果你有信心可以编写一个工作流程来解决你的特定问题,那么 GitHub Actions 将会是一笔多么宝贵的资产。
常问问题
如果我不知道 Kotlin 怎么办?
我认为编程语言的选择并不重要,只要它不是 Bash 就行。我的意思是,任何具有良好 IDE 支持的现代编程语言都可以胜任这项任务。
我们这里只做了一些基本的事情。我们 Workflow通过调用 workflow()then jobthen run("my command")或 uses(MyActionWithParameters(....))
唯一的问题是您需要安装 IntelliJ IDEA 社区版, 但它是免费且非常棒。
有什么缺点吗?
如果您在提交之前未运行 Kotlin 脚本,或者忘记提交 YAML 文件,或者直接编辑 YAML 文件,YAML 和 Kotlin 代码将不同步。我们提供了一致性检查,以便在出现这种情况时提前失败。只需使用 即可 workflow.writeToFile(addConsistencyCheck = true)。代价是持续集成 (CI) 速度会慢 15 秒左右。
GitHub 的 YAML 功能众多,您可能会遇到一些库尚未支持的功能。我们提供了一个 类型不安全的替代方案 来弥补这些缺陷。您也可以查看 未解决的问题 或创建自己的问题。
IntelliJ 不支持 Kotlin 脚本,但它支持常规的 Kotlin 编程。希望这种情况能随着时间的推移得到改善。
编译和运行 Kotlin 脚本比你习惯的 Python 或 JavaScript 等解释型语言要慢。但它仍然比在 CI 上提交、推送并等待 10 分钟要快两个数量级。
如果你在团队中使用它,你必须确保你的同事明白这个 YAML 文件是由 Kotlin 脚本生成的。请注意,第一行 YAML 代码如下: # This file was generated using Kotlin DSL (.github/workflows/hello_world_workflow.main.kts).
欢迎您向他们发送我的文章链接:)
我是 GitHub Action 维护者,我可以帮忙吗?
是的!
规范中缺少的 action.yml是每个输入参数的类型。我们目前正在 将这些信息添加到我们的代码库中, action-types.yml但如果能像 一些优秀的早期采用者那样, 将其放在您自己的代码库文件中,那就更好了 。
请参阅 https://github.com/krzema12/github-actions-typing
链接
本文的标题取自 Michel Pardo 的演讲 《Kotlin:Java 6 Wasteland 中的新希望》, 该演讲当年曾让人想转向 Kotlin。
完结
朋友们,就这些了。非常感谢你们让我走到今天。
我特别高兴能够回来写文章,这是我近一年来一直没能做到的事情。
如果您尝试一下,我很乐意听到您的反馈。
鏂囩珷鏉ユ簮锛�https://dev.to/jmfayard/github-actions-a-new-hope-in-yaml-wasteland-1i9c