#!/usr/bin/env bash # ============================================================================== # Copyright (C) 2021 Potherca # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. # ============================================================================== # There are a few standards this code tries to adhere to, these are listed below. # # - Code follows the BASH style-guide described at: # http://guides.dealerdirect.io/code-styling/bash/ # # - Variables are named using an adaption of Systems Hungarian explained at: # http://blog.pother.ca/VariableNamingConvention # # ============================================================================== set -o errexit # Exit script when a command exits with non-zero status. set -o errtrace # Exit on error inside any functions or sub-shells. set -o nounset # Exit script on use of an undefined variable. set -o pipefail # Return exit status of the last command in the pipe that exited with a non-zero exit code # ============================================================================== # Git Clone All Projects in GitHub Organisation # ------------------------------------------------------------------------------ ## Usage: $0 [-dh] ## ## Where: ## - is the domain where github lives (for instance: 'github.com') ## - is the ID of the group who's repos should be cloned ## - is the API access token to make REST API calls with ## ## Options: ## -d|--dry-run Only list the repositories, without actually cloning them ## -h|--help Print this help dialogue and exit ## -u|--user The given ID is a user, not a organisation ## ## The repositories will be cloned into a sub-directory under the path from Where ## this script has been called. The repository will be cloned into ./${group-id}/${repo-name} ## ## The git executable can be overridden by setting the GIT environmental variable ## before calling this script: ## ## GIT=/usr/local/git-plus $0 # ============================================================================== : readonly "${GIT:=git}" usage() { local sScript sUsage readonly sScript="$(basename "$0")" readonly sUsage="$(grep '^##' <"$0" | cut -c4-)" echo -e "${sUsage//\$0/${sScript}}" } github-clone-projects() { local -a aParameters aRepos local g_sGithubDomain g_sGithubToken g_sId local bIsUser bDryRun local sDirectory sRepo sRepos call-api() { local -r sSubject="${1?One parameter required: }" curl --silent -u "username:${g_sGithubToken}" "https://api.${g_sGithubDomain}/${sSubject}?per_page=100" } fetch-projects() { local iId sSubject readonly sSubject="${1?Two parameters required: }" readonly iId="${2?Two parameters required: }" call-api "${sSubject}/${iId}/repos" \ | grep -E -o '"ssh_url"\s*:\s*"[^"]+"' \ | cut -d '"' -f4 } fetch-group-projects() { local -r iId="${1?One parameters required: }" fetch-projects 'orgs' "${iId}" } fetch-user-projects() { local -r iId="${1?One parameters required: }" fetch-projects 'users' "${iId}" } bIsUser=false bDryRun=false aParameters=() for arg in "$@";do case $arg in -h|--help ) usage exit ;; -d|--dry-run ) readonly bDryRun=true shift ;; -u|--user ) readonly bIsUser=true shift ;; * ) aParameters+=( "$1" ) shift ;; esac done readonly aParameters readonly g_sGithubDomain="${aParameters[0]?Three parameters required: }" readonly g_sId="${aParameters[1]?Three parameters required: }" readonly g_sGithubToken="${aParameters[2]?Three parameters required: }" if [[ "${bIsUser}" = 'true' ]];then readonly sRepos=$(fetch-user-projects "${g_sId}") else readonly sRepos=$(fetch-group-projects "${g_sId}") fi aRepos=() for sRepo in ${sRepos[*]}; do aRepos+=("${sRepo}") done echo ' =====> Found ' ${#aRepos[@]} ' repositories' for sRepo in "${aRepos[@]}"; do # Grab repo name sDirectory="$(echo "${sRepo}" | grep -o -E ':(.*)\.')" # Lowercase the name sDirectory="$(echo "${sDirectory}" | tr '[:upper:]' '[:lower:]')" # Prepend the current location sDirectory="$(realpath --canonicalize-missing --relative-to=./ "${sDirectory:1:-1}")" if [[ -d "${sDirectory}" ]];then echo " -----> Skipping '${sRepo}', directory '${sDirectory}' already exists" else echo " -----> Cloning '${sRepo}' into directory '${sDirectory}'" if [[ "${bDryRun}" != 'true' ]];then mkdir -p "${sDirectory}" "${GIT}" clone --recursive "${sRepo}" "${sDirectory}" \ || { rm -rf "${sDirectory}" echo -e "\n ! ERROR !\n Could not clone ${sRepo}" } echo "" fi fi done } if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then export -f github-clone-projects else github-clone-projects "${@}" exit $? fi #EOF