這是我參與更文挑戰的第12天,活動詳情檢視:更文挑戰
任何東西都有丟失的可能性,除非你在丟失前做好了備份!本文將講解如何使用 GitHub Actions 實現自動備份程式碼倉。
目標
本文的目標是將 GitHub 使用者 user-a
下的所有程式碼倉同步到 GitHub 使用者 user-b
下。
準備
新建一個程式碼倉,程式碼倉的目錄結構下面這樣:
.
├── .github
│ └── workflows
│ └── mirror.yaml
複製程式碼
並在程式碼倉中設定三個 Secret,分別是:
GH_TOKEN_A
對應 GitHub 使用者user-a
的 AccessTokenGH_TOKEN_B
對應 GitHub 使用者user-b
的 AccessTokenSLACK_WEBHOOK
對應 Slack WebHook 地址(可選)
工作流
獲取程式碼倉列表
使用 GitHub CLI gh
獲取 GitHub 使用者 user-a
下的所有程式碼倉
echo ${GH_TOKEN_A} > gh_token_a # 將 user-a 的 GitHub AccessToken 寫入檔案
gh auth login --with-token < gh_token_a # GitHub CLI 登入
gh repo list user-a -L 1000 > a_repos # 獲取 user-a 的所有程式碼倉並寫入檔案
cat a_repos # 顯示程式碼倉列表
cat a_repos | wc -l # 顯示程式碼倉總數
複製程式碼
建立同名程式碼倉
在 GitHub 使用者 user-b
下建立同名程式碼倉。
gh repo create user-b/${repo_name} --private --description "${repo}" -y || true # 忽略錯誤,程式碼倉可能已經存在
複製程式碼
克隆程式碼倉
使用 --bare
引數克隆 GitHub 使用者 user-a
下的程式碼倉。
git clone --bare https://${GH_TOKEN_A}@github.com/user-a/${repo_name}.git ${repo_name}
複製程式碼
推送程式碼
使用 --all
和 --mirror
引數分別進行程式碼推送,防止推送的資料過大導致推送失敗。
--all
表示推送所有的分支--mirror
表示推送refs/
下的所有引用,包括分支、標籤等
cd ${repo_name}
mirror_repo="https://${GH_TOKEN_B}@github.com/user-b/${repo_name}.git"
git push --all -f ${mirror_repo} || true
git push --mirror -f ${mirror_repo} || true
複製程式碼
優化
- 忽略體積過大或者不需要備份的程式碼倉
# 為了保證程式碼倉名稱判斷的準確性,在定義和判斷時,在每個程式碼倉名稱的左右新增斜杆
IGNORE_REPOS="/repo_a/repo_b/"
[[ ${IGNORE_REPOS} =~ "/${repo_name}/" ]] && continue || true
複製程式碼
- 對於
tag
數量太多的程式碼倉,僅備份分支
ONLY_BRANCH_REPOS="/repo_c/repo_d/"
[[ ${ONLY_BRANCH_REPOS} =~ "/${repo_name}/" ]] && continue || true
複製程式碼
- 由於 GitHub Actions 的時區為
UTC
,定時任務的時間需要-8h
週一到週五的凌晨2點:
- 一般配置:
0 2 * * 1-5
- GitHub Actions 定時任務:
0 18 * * 0-4
完整的工作流配置
.github/workflows/mirror.yaml
檔案的內容:
name: Mirror repos
on:
schedule:
- cron: "0 18 * * 0-4" # 設定定時任務,週一到週五的凌晨2點進行備份
workflow_dispatch: # 手動觸發構建
jobs:
mirror:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: GitHub CLI version
run: gh --version
- name: List repos
env:
GH_TOKEN_A: ${{ secrets.GH_TOKEN_A }}
run: |
echo ${GH_TOKEN_A} > gh_token_a
gh auth login --with-token < gh_token_a
gh repo list user-a -L 1000 > a_repos
cat a_repos
cat a_repos | wc -l
- name: Mirror repos
env:
GH_TOKEN_A: ${{ secrets.GH_TOKEN_A }}
GH_TOKEN_B: ${{ secrets.GH_TOKEN_B }}
IGNORE_REPOS: "/repo_a/repo_b/"
ONLY_BRANCH_REPOS: "/repo_c/repo_d/"
run: |
echo ${GH_TOKEN_B} > gh_token_b
gh auth login --with-token < gh_token_b
mkdir repos
cd repos
set -x
cat ${GITHUB_WORKSPACE}/a_repos | while read repo; do
repo_name=$(echo ${repo} | awk '{print $1}' | awk -F/ '{print $2}')
[[ ${IGNORE_REPOS} =~ "/${repo_name}/" ]] && continue || true
gh repo create user-b/${repo_name} --private --description "${repo}" -y || true
rm -rf ${repo_name}
git clone --bare https://${GH_TOKEN_A}@github.com/user-a/${repo_name}.git ${repo_name}
cd ${repo_name}
mirror_repo="https://${GH_TOKEN_B}@github.com/user-b/${repo_name}.git"
git push --all -f ${mirror_repo} || true
[[ ${ONLY_BRANCH_REPOS} =~ "/${repo_name}/" ]] && continue || true
git push --mirror -f ${mirror_repo} || true
cd -
done
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
複製程式碼