GithubAction配置private仓库自动从public仓库同步的方法

本文介绍一种基于github action的解决方案用于实现private项目自动从public项目同步

需求

GitHub 提供了许多用于实现仓库同步的 Action,有些只支持 fork,而有些则支持两个独立的仓库。
对于 fork 项目,建议直接使用 GitHub Pull。本文将讨论非 fork 项目的同步问题。

有些开源项目,出于备份或私有部署的目的,需要克隆一份。 然而,由于 fork 的项目不能设置为 private,这就引发了隐私问题, 因为你可能不希望所有人知道你 fork 了某个项目。 一般的做法是将 public 项目克隆下来,然后推送到自己的 private 仓库。 这一过程可以直接使用 GitHub 的 import repository 功能实现。但这样由于失去了 fork 关系,导致无法使用 “Sync fork” 进行项目同步。

为了解决这个问题,我们可以使用 aormsby/Fork-Sync-With-Upstream-action 来实现独立项目的同步。 虽然有很多独立项目同步的 Action,但它们大多基于 Git 实现,这导致上游项目的所有变更都会同步到下游,包括 .github/workflows 下的文件。 这可能会导致 GitHub 任务在对 Action 进行操作时报错,因为这超出了默认的 GITHUB_TOKEN 的权限范围。

如果是 fork 项目,可以直接手动执行 “Sync Fork” 操作。否则,就需要创建更高权限的 token。

独立项目的同步action还有很多,不过都有一个问题,因为他们的实现都是基于git的,所以上游项目的所有变更都会同步到下游,这其中就包括了 .github/workflows 下的文件。会导致github认为该action在对action进行操作,这超出了默认的GITHUB_TOKEN的权限范围

缺少权限时的报错信息:(refusing to allow a GitHub App to create or update workflow .github/workflows/xxx.yml without workflows permission)
这时应使用有workflow权限的自定义token

设计

仓库同步可以基于 aormsby/Fork-Sync-With-Upstream-action 实现。
由于不想在 Action 中配置源仓库的地址,可以约定仓库名称为 ${repoName}-syncfrom-${userName},将远程库的信息存在项目名中,实现 Action 的通用化。
当然,这取决于个人需求。

ACTION_TOKEN 配置说明

  1. 在个人设置中创建具有完整 repo、workflow 权限的 Personal Access Token。
  2. 在仓库的设置中,添加名为 ACTION_TOKEN 的 secret,值为上一步获取的 Personal Access Token。

此外,需要在项目的设置中配置 Action:

  1. 将 Actions 权限设置为 Allow all actions and reusable workflows。
  2. 将 Workflow 权限设置为 Read and write permissions。

action示例

Action 文件的名称应独特,不与上游仓库的 Action 文件名重复,例如 .github/workflows/super-sync-from.yml
如果上游仓库对 .github/workflows/ 下的文件进行变更,则需要在 actions/checkout 步骤中使用具有 workflow 权限的 token。

无需修改版本(适用于项目名${repoName}-syncfrom-${userName})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
name: Public Upstream Sync

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
sync_latest_from_upstream:
name: Sync latest commits from upstream repo
runs-on: ubuntu-latest

steps:
# 标准签出
- name: Checkout target repo
uses: actions/checkout@v4
# 如果上游仓库有对.github/workflows/下的文件进行变更,则需要使用有workflow权限的token
# with:
# token: ${{ secrets.ACTION_TOKEN }}

- name: Extract Repo and User
id: extract
run: |
repository_name=${{ github.event.repository.name }}
if echo "$repository_name" | grep -qE '(.+)-syncfrom-(.+)'; then
repoName=$(echo "$repository_name" | sed -E 's/(.+)-syncfrom-(.+)/\1/')
userName=$(echo "$repository_name" | sed -E 's/(.+)-syncfrom-(.+)/\2/')
echo "RepoName: $repoName"
echo "UserName: $userName"
echo "repoName=$repoName" >> $GITHUB_ENV
echo "userName=$userName" >> $GITHUB_ENV
else
echo '无法从仓库名中提取 repoName 和 userName,格式应为 ${repoName}-syncfrom-${userName},当前为:'$GITHUB_REPOSITORY
exit 1
fi

# 获取分支名
- name: Get branch name (merge)
if: github.event_name != 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_ENV
- name: Get branch name (pull request)
if: github.event_name == 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / -)" >> $GITHUB_ENV

# 运行同步动作
- name: Sync upstream changes
id: sync
uses: aormsby/[email protected]
with:
upstream_sync_repo: ${{ env.userName }}/${{ env.repoName }}
upstream_sync_branch: ${{ env.BRANCH_NAME }}
upstream_pull_args: --allow-unrelated-histories --no-edit
target_sync_branch: ${{ env.BRANCH_NAME }}
target_repo_token: ${{ secrets.GITHUB_TOKEN }}
test_mode: false

定制化版本

对于已有的不想改名的,直接配置上流仓库名即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
name: Public Upstream Sync

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
sync_latest_from_upstream:
name: Sync latest commits from upstream repo
runs-on: ubuntu-latest

steps:
# 标准签出
- name: Checkout target repo
uses: actions/checkout@v4
# 如果上游仓库有对.github/workflows/下的文件进行变更,则需要使用有workflow权限的token
# with:
# token: ${{ secrets.ACTION_TOKEN }}

# 获取分支名
- name: Get branch name (merge)
if: github.event_name != 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_ENV
- name: Get branch name (pull request)
if: github.event_name == 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / -)" >> $GITHUB_ENV

# 运行同步动作
- name: Sync upstream changes
id: sync
uses: aormsby/[email protected]
with:
upstream_sync_repo: [替换成目标仓库名称]
upstream_sync_branch: ${{ env.BRANCH_NAME }}
target_sync_branch: ${{ env.BRANCH_NAME }}
target_repo_token: ${{ secrets.ACTION_TOKEN }}
upstream_pull_args: --allow-unrelated-histories --no-edit
test_mode: false


GithubAction配置private仓库自动从public仓库同步的方法
https://linshenkx.github.io/github-private-repo-sync-from-public-repo/
作者
John Doe
发布于
2023年12月17日
许可协议