🍵

GitLabで指定したグループ内の全てのリポジトリを一括でcloneする

2023/01/30に公開

概要

1個1個丹精込めて手動でcloneすることに限界を感じたので、一括で自分に関連するリポジトリをcloneする

シェルスクリプト

.zshrc
# リポジトリのディレクトリを作成してからcloneする
# 第1引数 URL(https://gitlab.example.com/diaspora/diaspora-client.git)
function git_clone_to_path() {
  [[ -z ${commands[git]} ]] \
    && { echo 'git is required'; return 1; }

  local repo_path=$(sed 's/[^:]*:\/\/[^\/]*\/\([^\.]*\)\.git/\1/' <<< $1 | xargs dirname)
  mkdir -p ${PWD}/${repo_path}
  (
    cd $2/${repo_path}
    [[ -d $(echo $1 | xargs basename | cut -d. -f1) ]] || git clone $1
  )
}

# APIがpaginationしているのでページ数を一旦取得
function gitlab_projects_total_pages_by_group_id() {
  [[ $# -eq 0 ]] && return 1

  local -r total=$(curl -i -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
    "https://gitlab.example.com/api/v4/groups/$1/projects?include_subgroups=true&simple=true&per_page=1" \
    | grep X-Total: | cut -d' ' -f2 | sed 's/[[:space:]]//')
  expr ${total} / 100 + 1
}

# 指定したGroupのリポジトリを全てcloneする
# 第1引数 Group ID(100)
function recursive_git_clone_to_path_by_group_id() {
  [[ -z ${commands[git]} ]] \
    && { echo 'git is required'; return 1; }
  [[ -z ${commands[jq]} ]] \
    && { echo 'jq is required'; return 1; }
  [[ $# -eq 0 ]] && return 1

  for i in $(seq $(gitlab_projects_total_pages_by_group_id $1)); do
    for repo in $(curl -s --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
      "https://gitlab.example.com/api/v4/groups/$1/projects?include_subgroups=true&simple=true&per_page=100&page=$i" \
      | jq -r '.[].http_url_to_repo'); do
      git_clone_to_path $repo
    done
  done
}

alias rgc='recursive_git_clone_to_path_by_group_id'
$ export GITLAB_TOKEN=xxxxx
$ rgc ${GROUP_ID} ${HOME}/workspace/test

Discussion