前言#
本人在前幾天將博客的 Shiro 換成了加了更多特性的贊助版主題 Shiroi(閉源)。由於原倉庫是私有倉庫,且不允許直接 Fork。在這種情況下,需要讓自己的倉庫和原倉庫保持定期同步,不想自己打命令行推,遂將目光轉向了 GitHub Actions,一邊踩坑一邊寫下此篇內容。
套輪子#
一般情況下,這種簡單的需求都會有寫好的輪子和前人的踩坑經驗,就看該怎麼套了(
類似的 Apps 和 Actions 模板有挺多,比如 Pull、GitHub 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/Fork-Sync-With-Upstream-action@v3.4.1
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_repo
、upstream_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 那就可以取消打勾正式跑一次了。
踩坑日記#
- CI 日誌顯示
fatal: could not read Username for 'https://github.com': No such device or address
後来看了一下原 issues 這算是不影響使用的已知 bug,就放著它吧
fatal: refusing to merge unrelated histories
這個問題出現在我手動解決衝突合完 PR 後的第二天,猜測是同步分支含私貨(自己修改的提交)導致的無法同步。沒辦法,只能手動拉取倉庫源代碼進行 force-push 了(
- 上游倉庫修改 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: "git@github.com: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 並在評估沒問題後合併,玩法還是挺多的。只能說偷懶 / 折騰是第一生產力(确信
此文由 Mix Space 同步更新至 xLog
原始鏈接為 https://zwh.moe/posts/technology/actions-sync