破事水 | Actions 同步上游项目及合并到自己分支

2024 年 4 月 14 日 星期日
/ , ,
24
1
AI 生成的摘要

破事水 | Actions 同步上游项目及合并到自己分支

前言

本人在前几天将博客的 Shiro 换成了加了更多特性的赞助版主题 Shiroi(闭源)。由于原仓库是私有仓库,且不允许直接 Fork。在这种情况下,需要让自己的仓库和原仓库保持定期同步,不想自己打命令行推,遂将目光转向了 GitHub Actions,一边踩坑一边写下此篇内容。

套轮子

一般情况下,这种简单的需求都会有写好的轮子和前人的踩坑经验,就看该怎么套了(

类似的 Apps 和 Actions 模板有挺多,比如 PullGitHub Sync 等,最后选了 aormsby/Fork-Sync-With-Upstream-action 作为轮子来写同步配置。支持用 Access Token 拉私有仓库,可以选择上游仓库和目标仓库的分支,有示例,非常的贴心。

轮子找好了,接下来新建一个专门与上游同步的 sync 分支,保证修改都在 main 分支上

好吧,那就新建个 workflow 文件写配置C/V官方示例吧。这里我建了一个 sync 分支用来保证与上游仓库的一致性,至于同步到 main 分支那就是接下来的事了(

name: 'Upstream Sync'

on:
  schedule:
    - cron:  '0 0 * * *'
    # 每天8点(UTC+8)执行

  workflow_dispatch:  # click the button on Github repo!
    inputs:
      sync_test_mode: # Adds a boolean option that appears during manual workflow run for easy test mode config
        description: 'Fork Sync Test Mode'
        type: boolean
        default: false

jobs:
  sync_latest_from_upstream:
    runs-on: ubuntu-latest
    name: Sync latest commits from upstream repo

    steps:
    # REQUIRED step
    # Step 1: run a standard checkout action, provided by github
    - name: Checkout target repo
      uses: actions/checkout@v3
      with:
        # optional: set the branch to checkout,
        # sync action checks out your 'target_sync_branch' anyway
        # 切到要同步的分支
        ref:  sync
        # REQUIRED if your upstream repo is private (see wiki)
        persist-credentials: false

    # REQUIRED step
    # Step 2: run the sync action
    - name: Sync upstream changes
      id: sync
      uses: aormsby/[email protected]
      with:
        target_sync_branch: sync
        # REQUIRED 'target_repo_token' exactly like this!
        target_repo_token: ${{ secrets.GITHUB_TOKEN }}
        upstream_sync_branch: main
        upstream_sync_repo: upstream/Shiroi
        upstream_repo_access_token: ${{ secrets.UPSTREAM_REPO_SECRET }}

        # Set test_mode true during manual dispatch to run tests instead of the true action!!
        test_mode: ${{ inputs.sync_test_mode }}
      
    # Step 3: Display a sample message based on the sync output var 'has_new_commits'
    - name: New commits found
      if: steps.sync.outputs.has_new_commits == 'true'
      run: echo "New commits were found to sync."
    
    - name: No new commits
      if: steps.sync.outputs.has_new_commits == 'false'
      run: echo "There were no new commits."
      
    - name: Show value of 'has_new_commits'
      run: echo ${{ steps.sync.outputs.has_new_commits }}

实际上需要修改的地方就几点,定时触发时间(cron),Step 1 中的 ref 和 2 中的 target_sync_branch 需一致且指向自己项目的同步分支(这里为 sync),上游仓库的信息和源分支(upstream_sync_repoupstream_sync_branch)。

写完工作流之后进行一下相关变量的配置。先准备一个能读取私有上游的 Access tokens,这里选 Classic,因为 Fine-grained tokens 似乎读不了所有权不属于自己的私有项目(存疑),权限给个 repo 大类即可。复制生成后的 token,来到仓库设置 -> Secrets and Variables -> Actions 添加个 Repository secrets。变量名写 UPSTREAM_REPO_SECRET,值就是刚才生成的 token,保存。再来到 Actions Setting,把 Workflow permissions 改成 Read and write 保存。

测试

来到自己配置的 Workflow 页面,把 Test Mode 勾上跑一次配置是否有问题(此时仅测试配置是否正确,不涉及对仓库的操作),看到所有配置都是 PASSED 那就可以取消打勾正式跑一次了。

踩坑日记

  1. CI 日志显示fatal: could not read Username for 'https://github.com': No such device or address

后来看了一下原 issues 这算是不影响使用的已知bug,就放着它吧

  1. fatal: refusing to merge unrelated histories

这个问题出现在我手动解决冲突合完 PR 后的第二天,猜测是同步分支含私货(自己修改的提交)导致的无法同步。没办法,只能手动拉取仓库源代码进行 force-push 了(

  1. 上游仓库修改 workflow 导致的同步失败,报错示例:
 ! [remote rejected] sync -> sync (refusing to allow a GitHub App to create or update workflow `.github/workflows/build.yml` without `workflows` permission)
error: failed to push some refs to 'https://github.com/wuhang2003/Shiroi.git'

在聊解决这个问题的方法之前,先大骂 GitHub Actions 所生成的 Token 就是个。为什么要这么说呢?

这是 Actions 所生成的一次性 Token 权限:

可以看到上面是有 Actions 写权限的,再看一下日志说的没有 workflow 权限,相信各位应该察觉到不对劲了,生成的 Token 权限和显示权限咋还不一致呢?这就是我想吐槽的地方。在官方的讨论区目前只搜到一个讨论与此有关,而且还没回复......

当然权限问题解决方法也很简单暴力,自己建一个带 workflow 和 repo 权限的 PAT 加入 sercets 代替已有的 ${{ secrets.GITHUB_TOKEN }} 就行了。

在这之后...

最开始我是仅使用上述工作流同步之后自己提 PR 合并到 main 来实现手动更新。但折腾几天下来,一来感觉太过繁琐不够懒,二来有冲突了还要自己动手解决也费劲。所以也在研究怎么自动提 PR/自动 merge 到 main 并 push。后来根据实际情况选择了 rebase(变基)的方式合并更改(变基介绍),好处是不会让自己的更改串整个 commit 流,而是统一堆在上游的 commit 之后。这里所使用的 workflow 是 tiacsys/git-rebase。直接在原 CI 配置 sync.yml 后增加 rebase 的步骤。配置如下:

- name: git-rebase
  uses: tiacsys/git-rebase@v1
  with:
    repo: "[email protected]:wuhang2003/Shiroi.git"
    source_branch: "main" # 待修改的主分支
    destination_branch: "sync" # 上游同步分支
    ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}

完事之后生成个提交的 SSH Key,公钥丢仓库的 deploy ssh 给写权限,私钥丢 Actions secret 设置为 SSH_PRIVATE_KEY 的值。完工!接下来可以点击按钮触发一下 Workflow 测试效果。

没啥问题,可以跑路了。

这样折腾下来,一个能保证定期同步(且支持手动触发)上游私有仓库并进行 rebase 后同步到 main 的工作流就写好了。当然,额外增加的 rebase 工作流也可以根据需要修改成 Merge 方式合并或者自动提 PR 并在评估没问题后合并,玩法还是挺多的。只能说偷懒/折腾是第一生产力(确信

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...