archlinuxcn / lilac

Lilac is the build bot for archlinuxcn
GNU General Public License v3.0
114 stars 40 forks source link

Github actions 打包支持 #149

Closed petronny closed 3 months ago

petronny commented 4 years ago

archlinuxcn/repo#1575

FAQ:

  1. 必要性何在 我觉得带有run_cmd的lilac.*其实都是不安全的,万一来一个rm -rf ~虽说不会搞炸系统但是也很恶心的,所以扔个docker里跑可能也挺好的 剩下的就是透明度啥的

  2. 和现有的lilac是什么关系 我打算把这个作为一个特殊的build_prefix交给lilac,即整体还是由lilac决定打哪些包和时序上的依赖关系 然后每个pkgbase都做一个专门的workflow,lilac通过发送一个内容为对应pkgbase的POST请求触发workflow 结束时一个artifact到这个workflow run,然后lilac下载这个artifact就可以和原来的lilac兼容

  3. 可否使用devtools 可以

  4. 依赖关系如何解决 首先前置依赖的包的artifact是60天有效。 然后对于一个有依赖的包,先查找依赖包的artifact还在不在,在的话直接下载这个; 如果artifact不在了,说明肯定超过60天了,mirror里肯定有,从合适的mirror下载即可。

  5. 缓存如何解决 github actions有缓存,不过只有5G大小。 建议是做一个叫pacman-cache-x86_64的缓存只用来缓存extra-x86_64-build下载的包。 repo_depends、source等的只能下载了

  6. 性能问题如何解决 虽然单个包的确慢,但结合 #145 的话,20个包并行打还是很好的。 对于某些特别吃资源的包,可以不用这个,还在本地打包。 后期的话希望lilac也由一个专门的workflow来运行,高性能服务器做一个self-hosted action runner

  7. 有无预览 我给无依赖的yay做了一个,可以参考 https://github.com/petronny/arch4edu/blob/master/.github/workflows/yay.yml 一个对应的运行实例在 https://github.com/petronny/arch4edu/actions/runs/113176984 打包结果和log在 https://github.com/petronny/arch4edu/suites/710761537/artifacts/6924885 https://github.com/petronny/arch4edu/suites/710761537/artifacts/6924884

  8. 目前还有何问题

    1. 自动下载依赖包没做了 我可以做一个python版本的,就是递归读一下yml,然后用github token/mirror下载 但最好是通过js实现并封装
    2. workflow配置文件巨长 调查了一下可以通过自定义action的做法封装一些固定操作 我写了一个预览版(就是假设actions都封装好了),见最后 应该和原来的lilac.*差不多了
    3. actions如何封装? 查了一下custom actions分为docker和js版两种。 我们应该是要用js版的,就是在js里调用各种shell命令,下载文件什么的 可以参考 https://github.com/actions/checkout , 这个就是通过git命令clone一个repo到当前目录,后面的steps可以读。 所以文件IO,命令执行什么的应该都是可行的。 不过有个问题是我js基本不会。。。所以需要帮助了。。。

name: yay

on:
  repository_dispatch:
    types: [yay]

jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: archlinux
      options: --privileged
      volumes:
        - /sys/fs/cgroup:/sys/fs/cgroup

    steps:
      - name: Initialize build environment
        uses: archlinuxcn/lilac/actions/initialize-extra-x86_64@master

      - uses: actions/checkout@master

      - uses: archlinuxcn/lilac/actions/aur-pre-build@master

      - name: Build package
        id: build
        uses: archlinuxcn/lilac/actions/extra-x86_64-build@master
        with:
          exclude_package: yay-test yay-test2
          repo_depends: a b/b
          archbuild_args:
          makechrootpkg_args:
          makepkg_args:

      - uses: archlinuxcn/lilac/actions/aur-post-build@master

      - uses: archlinuxcn/lilac/actions/post-process@master
lilydjwg commented 4 years ago

1. 安全性的话,其实也有办法,比如 userns + bind mount 或者 syscall filter 限制一下就好了。编译机上了 cgroups v2,所以 docker 已经跑不动了。

2. 不要搞特殊哇。新建个 runner 字段多好。

6. 那就先把 #145 给解决了。

8. 为什么要用 js 啊,那些 pre/post_build,不能调 Python 的吗?

petronny commented 4 years ago

2. 都可以😂 临时的话写一个build_prefix = actions-extra-x86_64就无痛和现在兼容了 比较方便验证

8. 如果前置环境配好了可以调用python的lilac

- run: |
          cd yay && ./lilac --pre_build_only
- uses: archlinuxcn/lilac/actions/extra-x86_64-build@master

或者就是直接用shell重写pre_build中自定义的部分,其他封装

- uses: archlinuxcn/lilac/actions/aur-pre-build@master
- run: |
          cd yay && sed 's/aaa/bbb/g' -i PKGBUILD
- uses: archlinuxcn/lilac/actions/extra-x86_64-build@master

我比较倾向后者,配置环境每个run都会做,少重复一点是一点 另外反正workflow都是新文件,不太麻烦的就重写 麻烦的就先不迁移了。。。

petronny commented 4 years ago

我决定优先推进一下这个了。。。 最近被国内的网络环境搞得有点烦。。。转移到github解决网络问题

我想了一下重新造一遍lilac的轮子还是不太好。。。 比如比较新老pkgver什么的。。。

总之我就做了一个完全兼容现有lilac.py的workflow https://github.com/petronny/arch4edu/blob/master/.github/workflows/build.yml 通过控制POST请求的参数可以指定运行某个包的lilac.py里的single_main 目前应该可以打出任何无依赖的包,比如:

下一步只要在single_main那里

  1. 通过lilac.yaml找到所有依赖
  2. 把所有依赖都下载好
  3. 把依赖都加到makechrootpkg_args里面

我觉得就目标达成了

问题与讨论

  1. 这个workflow可以在任何repo里运行,理论上可以通过开马甲来突破cache 5GB限制
  2. lilac 使用的 https://github.com/petronny/lilac 干掉了kill_children和build_cleaner docker环境中应该不需要了吧?
  3. 部分脚本封装在了 https://github.com/petronny/action-tools 不写 js 那套了。。。直接执行得了。。。
  4. 这个workflow还有其他问题么?
  5. 其实每个包一个独立workflow的我也写了,参考 https://github.com/petronny/arch4edu/blob/master/.github/workflows/yay.yml 做好了以后可以把lilac.yaml和lilac.py都吃了 但缺点就是需要做lilac API 向 action-tools 中的 API 的迁移 所以 这个lilac兼容的共享workflow 和 独立workflow 如何取舍为好。。?
lilydjwg commented 4 years ago

这个 container 选项指定的 container 是哪里来的?

GitHub Actions 的免费配额和限制文档在哪里来着?

kill_children 除了超时处理外,也用于大日志的处理,所以还是需要的(除非你想等着有问题的构建把所有可用空间写完然后等超时)。

你是想让每个包独立跑,还是你在服务器上跑一个 lilac 实例来调度?

复用 lilac 的代码吧,那么多 api 函数你重新实现起来也挺费事的。

我想比较好的方案是,只把更新检查和构建过程交给 github actions,剩下的事务还是由 lilac 处理。single_main 是给本地跑来测试用的,我们可以再为 github actions 搞一个 github_main,在其中做依赖包下载之类的事情。

petronny commented 4 years ago

这个 container 选项指定的 container 是哪里来的?

应该是docker hub,这里有个测试第三方container的例子 https://github.com/petronny/docker-image/actions/runs/111211548

GitHub Actions 的免费配额和限制文档在哪里来着?

对公有repo没有限额,只对私有有限额。 主要限制是运行实例的限制和cache的限制

你是想让每个包独立跑,还是你在服务器上跑一个 lilac 实例来调度?

本地服务器上跑一个 lilac 实例来调度,每个包由build.yml派生一个独立的runner打包。runner之间可以并行。 lilac先运行pre_build()函数用于比较新老pkgver,如果新的比老的老就报错。 然后调用github actions。 actions内部重复执行一遍pre_build(),然后打包。 执行一个独立的action_post_build(),(比如用来把不想要的包删了,就不用上传了) 打包完成后上传包、PKGBUILD等、log到artifact。 lilac的post_build()的内容为下载后,包存本地,PKGBUILD等更新,log保存到对应变量中。 之后应该就能跟后面的创建commit、签名包等对上了。

kill_children 除了超时处理外,也用于大日志的处理,所以还是需要的(除非你想等着有问题的构建把所有可用空间写完然后等超时)。

那也不应该是kill_children,直接通过API把这个workflow取消就行

只把更新检查和构建过程交给 github actions

检查更新也可以么?其实nvchecker的话,加个proxy的选项应该就能解决网络问题。。。

github actions 搞一个 github_main

那就action_main吧,可以通过sys.argv[1]区分。 不过目前不冲突,我可以先实现着。。。

首先前置依赖的包的artifact是60天有效。 然后对于一个有依赖的包,先查找依赖包的artifact还在不在,在的话直接下载这个; 如果artifact不在了,说明肯定超过60天了,mirror里肯定有,从合适的mirror下载即可。

我在想要不artifact不在了,说明肯定超过60天了,那也就rebuild一遍得了? rebuild一些很久之前包可能能帮助解决一些问题?

lilydjwg commented 4 years ago

应该是docker hub

这个么?

另外我看到你的 initialize.sh 脚本里安装了一些依赖包。这个可能会导致打出来的包隐式地依赖上这些包。是否可能再调用 archbuild 脚本来打包?

对公有repo没有限额

所以可以跑需要运行很长时间的任务?

那也不应该是kill_children,直接通过API把这个workflow取消就行

嗯,有 API 那就用 API。

检查更新也可以么?其实nvchecker的话,加个proxy的选项应该就能解决网络问题。。。

实际上 nvchecker 是最容易搬上 github actions 上的呀。当然你不想搬也可以不搬。

我在想要不artifact不在了,说明肯定超过60天了,那也就rebuild一遍得了?

可以是可以。但是这就会导致不必要的依赖包更新呢。虽然可能解决一些问题,但也会引出另一些问题。

  1. pkgrel 一直涨一直涨,用户也要每两个月更新一个包
  2. 要是这次打包失败了怎么办?比如源码所在的网站宕机了啥的
petronny commented 4 years ago

这个么?

我觉得是

是否可能再调用 archbuild 脚本来打包

现在就是调用的archbuild,log里可以看到

微信截图_20200611163627

所以可以跑需要运行很长时间的任务?

时间是6小时。先把简单的包搬上去,之后可能通过自建runner把其他搬上去吧。。。

pkgrel 一直涨一直涨,用户也要每两个月更新一个包

那可能就不做这个了吧。。。

petronny commented 4 years ago

我做了一个带依赖打包的预览了 https://github.com/petronny/arch4edu/actions/runs/132493800

目前还是只从repo下载,从artifact下载WIP

主要功能:

petronny commented 4 years ago

(终于打出了因为网络问题失败好几周的包,老母亲留下了欣慰的泪水)

lilydjwg commented 4 years ago

试试使用这个处理包下载?

https://github.com/archlinuxcn/lilac/blob/gh-actions/lilac2/remote/gh_actions.py

我不知道当前用户有没有 /var/cache/pacman/pkg 的写权限。如果没有,需要换一个目录来放下回来的缓存文件。

另外这个缓存需要手动管理么?还是 github 会自动删掉过多的文件呀?

petronny commented 4 years ago

试试使用这个处理包下载?

可能得等等了,今天打算做一个简单的 action-extra-x86_64-build ,然后把后面跟lilac对接的先都走通。然后就得下周末才有时间了。。。

不过初步看了一下,从repo下载那,我觉得目前的alpm下载相对于download-package-from-artifact.sh的pacman自带下载还有这些问题:

  1. 前一个mirror失败了自动尝试下一个 repo
  2. 下载完自动校验 gpg

另外这个缓存需要手动管理么?还是 github 会自动删掉过多的文件呀?

当前的cache使用方式是 每次把cache文件夹由 https://github.com/actions/cache 快照成一个cache-时间.zst交给github,github 下次就会找一个最新的cache-时间.zst恢复出来 (我觉得这样最适合pacman的cache)

限制为所有快照文件的容量为5G,超了就会从老的开始删,直到小于 5G 我猜如果最后一个cache-时间.zst> 5G 了,那么所有的cache就都被删了,就没有cache了。

所以最好就是在不超过5G的情况下尽可能多塞东西。。。

据我之前的观察,如果不存repo_depends,剩下的差不多就是5G 所以我建议repo_depends不要放 /var/cache/pacman/pkg,就每次下载吧。。。 我目前存的 ~/repo_depends

如果某个特定包经常要下大repo_depends,可能得开个马甲repo只打这个包,这样就独享一个5G cache

lilydjwg commented 4 years ago

我觉得目前的alpm下载相对于download-package-from-artifact.sh的pacman自带下载还有这些问题

这些应该都有。不过 gpg 需要设置好。记得把 keyring 包装上应该就好了。我测试的时候,截断文件它会报告校验和错误,所以我不确定它有没有用 gpg……

所以我建议repo_depends不要放 /var/cache/pacman/pkg,就每次下载吧。。。

可以。去把 utils.py 里那个路径改了就行了。

petronny commented 4 years ago

记得把 keyring 包装上应该就好了。

我觉得这样不好。。。最好是专门做一个 gpgdir pacman-key --init --gpgdir gnupg pacman-key --populate third_party 然后pacman 只从这个gpgdir校验

lilydjwg commented 4 years ago

啊,pyalpm 没实现 questioncb……指定 gpgdir 倒是没有问题。

lilydjwg commented 4 years ago

看了一下,实现 questioncb 并不困难。需要的话我有空 pr 一个。

算了,既然不要缓存的话,暂时用不着回答问题。

petronny commented 4 years ago

从artifact下载包还有个冒号的问题 就是文件名的:我都替换成了COLON 否则不让上传。。。 下载后得自己换回来。。。

lilydjwg commented 4 years ago

On Fri, Jun 12, 2020 at 06:30:34AM -0700, Jingbei Li wrote:

从artifact下载包还有个冒号的问题 就是文件名的:我都替换成了COLON 否则不让上传。。。 下载后得自己换回来。。。

囧……不过 pacman 应该不会在意那个的。

-- Best regards, lilydjwg

petronny commented 4 years ago

action-extra-x86_64-build第一版出现了: 已更新第二版

#!/bin/sh
set -e

export TOKEN=

repo=petronny/arch4edu

package=$(realpath .)
package=$(basename $package)
uuid=$(uuidgen)

curl -sS -X POST https://api.github.com/repos/${repo}/dispatches \
        -H "Accept: application/vnd.github.everest-preview+json" \
        -H "Authorization: token $TOKEN" \
        --data "{\"event_type\": \"$package $uuid\"}"

while true
do
        sleep 30
        download-file-from-artifact.zsh \
                --repo ${repo} \
                --file $package.$uuid \
                --type file \
                --save-path . 2>/dev/null || continue
        break
done

mv $package.$uuid workflow_id

workflow_id=$(cat workflow_id)

download-file-from-artifact.zsh \
        --repo ${repo} \
        --workflow $workflow_id \
        --file $package.log \
        --type file \
        --save-path /tmp \
        --save-json artifact.json || (echo "Error:\tDownload $package.log failed" && exit 1)

cat /tmp/$package.log

download-file-from-artifact.zsh \
        --repo ${repo} \
        --workflow $workflow_id \
        --file $package.patch \
        --type file \
        --save-path /tmp || (echo "Error:\tDownload $package.patch failed" && exit 1)

for i in $(git status -s | grep " M" | cut -c 4-)
do
        git checkout -- $i
done

for i in $(git status -s | grep "^A" | cut -c 4-)
do
        [ $(basename $i) = artifact.json ] && continue
        [ $(basename $i) = workflow_id ] && continue
        rm $i
done

git add workflow_id artifact.json

git apply /tmp/$package.patch

download-file-from-artifact.zsh \
        --repo ${repo} \
        --workflow $workflow_id \
        --file $package \
        --type package \
        --save-path . || (echo "Error:\tDownload $package failed" && exit 1)

action_main也好了。整体配套是这样

#!/usr/bin/env python3
from lilaclib import *

maintainers = [{'github': 'petronny', 'email': 'Jingbei Li <i@jingbei.li>'}]
update_on = [{'aur': None}]
build_prefix = '/path/to/action-extra-x86_64'
pre_build = aur_pre_build
post_build = aur_post_build

if __name__ == '__main__':
    from action_tools import action_main
    action_main(build_prefix)

sys.argv[1]是'action'的时候(action中运行的时候会加这个参数) action_main会下载repo_depends,并去掉build_prefix中的.*action- 然后启动single_main

没有action参数就会退化成 single_main

问题与讨论

1. 现在有4个从artifact下载东西的sh...

这4个应该是要合并成一个函数的,但我shell不太会写argparse...先分成4个了。。。

2. 有关uuid 首先github没有通过event_type检索workflow runs的API... 我想了一个通过uuid匹配的办法,应该可以应对所有情况(并行、并发等)

3. 执行 action-extra-x86_64-build 前,lilac会运行一次pre_build action-extra-x86_64-build 执行中,workflow中也会运行一次pre_build,并把最终的改动传一个commit patch到artifact 所以 workflow 结束后,action-extra-x86_64-build 要把本地的所有改动都扔了 然后直接应用从artifact下载的patch就行了

我有个问题是把本地的所有改动都扔了这个怎么做。。。 改删好办,新文件的情况咋处理。

或者有更好的解决办法么。。。

lilydjwg commented 4 years ago

这4个应该是要合并成一个函数的,但我shell不太会写argparse...先分成4个了。。。

这就是为什么我要用 Python。

我有个问题是把本地的所有改动都扔了这个怎么做。。。

你是要 git clean -xfd

petronny commented 4 years ago

看了一下,实现 questioncb 并不困难。需要的话我有空 pr 一个。

能顺便帮忙pr一个pacman -Sww package就可以无视依赖下载包么? 当时找了半天发现竟然没有这个功能。。。

你是要 git clean -xfd?

下周再看[捂脸]

lilydjwg commented 4 years ago

能顺便帮忙pr一个pacman -Sww package就可以无视依赖下载包么?

pacman -Swd 不行么?

petronny commented 4 years ago

pacman -Swd 不行么?

貌似是 pacman -Swdd

但我shell不太会写argparse

我打算zsh试试。。。

petronny commented 4 years ago

发现了一个小问题

list all artifacts 这个API得通过翻页才能列出所有的 artifacts

目前这个API在以下几处用到了:

  1. 监控某任务是否已经完成(即pkgname.uuid文件有没有出现) 这个只需要看最新的artifacts应该就行了,比如前100个吧 这个只在本地运行

  2. 从所有artifact里找一个最新的某包 这个只在workflow run里运行 这个很要命,所有包都查一遍肯定是不好的

我想了以下解决办法:

  1. 首先不需要从所有artifact里找,从2天内的artifact里找肯定没问题了
  2. 在所有workflow runs之间传递一个artifacts list文件 每个workflow run启动开始, 先从所有artifact里找一个最新的artifacts list,除了首次运行之外应该不会翻很多页了 维护artifacts list到最新,且把2天外的老artifacts从list中去掉 最后上传

但感觉传文件这里文件重复度有点高, 但不这么干的话,如果都传到同一个地方(比如repo)就有一些并发问题要解决 有啥好的解决办法么。。。

lilydjwg commented 4 years ago

list all artifacts 这个API得通过翻页才能列出所有的 artifacts

你才发现啊……翻页我那个分支里已经做了处理了。

你会有很多页么?不多的话应该没太大关系,如果太多就把太旧的删掉?

petronny commented 4 years ago

应该会有很多吧

一个包传4个文件,假设每天100个包,60天,100个每页,总计240页。

lilydjwg commented 4 years ago

呃,那看来得用 v4 了……

petronny commented 4 years ago

不过可以限制到只找2天内的。8页吧。

虽然我觉得还是有点多

100个包都找8页也800次请求了,并且可能会比100个包多。。。 因为绝大多数都能搬上去

petronny commented 4 years ago

我想了一下其实貌似可以不冲突? 如果每个workflow run最后都只提交自己这个run里的artifacts的话 肯定不会冲突

感觉可以

while true
do
  git push && break || git pull --rebase
done

有个问题,这个repo可不可以和存lilac.py的repo是一个?就是和lilac.py存一块 感觉上是同一个的话比较符合认识? 打开目录的同时就能查到文件下载链接,上次运行的workflow_id什么的

就是多存一个artifacts.json和(可选)workflow_id

petronny commented 4 years ago

现在有4个从artifact下载东西的sh...

4合1了。https://github.com/petronny/action-tools/blob/master/download-file-from-artifact.zsh

petronny commented 4 years ago

action-extra-x86_64-build第二版 能正常工作了

现在 arch4edu 的 ncurses5-compat-libs 和 vim-youcompleteme-git 就是action-extra-x86_64-build 打包的了,调用的是petronny/arch4edu这个马甲的action,产生的commit见下

https://github.com/petronny/arch4edu/actions/runs/134418854 https://github.com/arch4edu/arch4edu/commit/91475c31b5894716a2aa8f7965026df88f387829

https://github.com/petronny/arch4edu/actions/runs/134422382 https://github.com/arch4edu/arch4edu/commit/b2c8fce3d6ac353ac3b9baa5e498da0c58447071

后续对接也正常。

就是多存一个artifacts.json和(可选)workflow_id

我目前就是把这俩都存了。我想了一下还是存repo里最好。 因为会有多个马甲repo来打包,要跨repo维护这个。 多个马甲比如:

(我们只能通过不同repo来调用不同的runner)

目前我是打算接着改造 action_tools,现在存了artifacts.json了,download_repo_depends那要改改了

petronny commented 4 years ago

就是多存一个artifacts.json和(可选)workflow_id

这里有个需求。。。就是能不能把lilac的最后一push改成每个都push 或者至少通过action打包的成功后push一下,否则这俩文件没法同步。。。

lilydjwg commented 4 years ago

On Tue, Jun 23, 2020 at 12:35:21AM -0700, Jingbei Li wrote:

就是多存一个artifacts.json和(可选)workflow_id

这里有个需求。。。就是能不能把lilac的最后一push改成每个都push 或者至少通过action打包的成功后push一下,否则这俩文件没法同步。。。

不能。月初的时候尝试过,结果出现了一些问题。

最主要的是,push 前必须 pull 任何新增的修改,造成 lilac 无法得到一致的仓 库内容。

有一种办法是 pull 和 push 操作另外放一个分支,当前批次 lilac 并不使用, 结束的时候再合并过来。实现起来挺麻烦。

-- Best regards, lilydjwg

petronny commented 4 years ago

那。。。实在不行就另开个仓库存吧。。。

也好,这样lilac改动更少了

lilydjwg commented 4 years ago

On Tue, Jun 23, 2020 at 01:09:17AM -0700, Jingbei Li wrote:

那。。。实在不行就另开个仓库存吧。。。

也好,这样lilac改动更少了

嗯,这主意不错。专门开个仓库存,保证 push 成功。

-- Best regards, lilydjwg

petronny commented 4 years ago

我把 action-extra-x86_64-build 整理到了 https://github.com/petronny/action-tools/blob/master/action-archbuild 以及配套有一个配置文件 https://github.com/petronny/action-tools/blob/master/config.sample.yaml

petronny commented 4 years ago

有一个需求。。。

我打算在lilac本地调用时,把pre_build post_build都跳过。 (这个可以通过build_prefix是不是action开头,或者一个叫什么use_action的变量控制) action中这两个会执行,最后都会反馈到最终的patch里,所以本地没有运行的必要

然而,在 https://github.com/archlinuxcn/lilac/blob/master/lilac#L128 这里要求_G.pkgver_G.pkgrel必须有值。 能不能改成直接从PKGBUILD中就可以读pkgver和pkgrel

另外这里我觉得有点奇怪,直接从PKGBUILD中就可以读了啊,为什么要用_G中的呢

lilydjwg commented 4 years ago

都跳过了,那你还用 lilac 干嘛呢。

用 _G 是因为,已经读到了,干嘛再读一次呢……

petronny commented 4 years ago

得用啊,不是计划的lilac来定哪些要打包及打包顺序调度,签名等等。。。

那。。。我还是判断一下吧。。。 就是post build遇action不跳过,override成一个固定的post_build,只负责读PKGBUILD写_G

lilydjwg commented 4 years ago

哦那个。计划是打包部分在 Actions 上运行,lilac 这边自然就不执行相应的代码了呀。

lilydjwg commented 3 months ago

While lilac has gained separate worker support, a GitHub worker is not planned.