本文介绍一种基于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 配置说明
在个人设置中创建具有完整 repo、workflow 权限的 Personal Access Token。
在仓库的设置中,添加名为 ACTION_TOKEN
的 secret,值为上一步获取的 Personal Access Token。
此外,需要在项目的设置中配置 Action:
将 Actions 权限设置为 Allow all actions and reusable workflows。
将 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 58 59 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 - 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 }} shallow_since: '1 days ago' 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 42 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 - 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 shallow_since: '1 days ago' test_mode: false