Last active
May 30, 2024 17:35
-
-
Save igstan/0a89b8bb1a6df0754647cdd87d8221b6 to your computer and use it in GitHub Desktop.
Clone all your GitHub gists, public or private.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Clones all gists (public or private) into directory `gists/` (auto-created | |
# and configurable if desired). The cloned gists are placed into directory | |
# names formed from the name of the first file found in the gist concatenated | |
# to the gist ID. For example, this gist will be cloned into: | |
# | |
# gists/clone-gists.sh-0a89b8bb1a6df0754647cdd87d8221b6 | |
# | |
# USAGE: | |
# | |
# 1. Get a token with gist reading permissions from here: | |
# https://github.com/settings/tokens?type=beta | |
# | |
# 2. Export your token in an env var called `GITHUB_GISTS_TOKEN`: | |
# | |
# $ export GITHUB_GISTS_TOKEN=<YOUR_TOKEN> | |
# | |
# 3. Execute script with default destination directory: | |
# | |
# $ ./clone-gists.sh | |
# | |
# Or with a custom destination directory: | |
# | |
# $ DST_DIR=my_gists ./clone-gists.sh | |
# | |
# SYNCING: | |
# | |
# On subsequent executions, the script will skip already cloned gists by | |
# default, but you can override that. This will effectively issue `git pull` | |
# commands inside the already cloned gists: | |
# | |
# $ SYNC=1 ./clone-gists.sh | |
# | |
# SSH CLONING | |
# | |
# By default, the script uses HTTP cloning, mostly because it's faster, but if | |
# you want it to use SSH, you can ask it to do that too: | |
# | |
# $ USE_SSH=1 ./clone-gists.sh | |
# | |
shopt -so errexit | |
shopt -so nounset | |
shopt -so pipefail | |
shopt -s lastpipe | |
log() { | |
printf '%s' "$@" | |
printf '\n' | |
} >&2 | |
declare -r token="${GITHUB_GISTS_TOKEN:?missing; create one at https://github.com/settings/tokens?type=beta}" | |
# Where should we put the gists? In "gists/" by default. | |
declare -r dst_dir=${DST_DIR:-gists} | |
# Should we update in case they're already cloned? Not by default. | |
declare -ri sync=${SYNC:-0} | |
# Should we clone using SSH? Not by default. | |
declare -ri use_ssh=${USE_SSH:-0} | |
# What external commands are we using? | |
declare -ra dependencies=(curl git jq) | |
gists() { | |
declare -r page=${1:-1} | |
declare -r url="https://api.github.com/gists?per_page=25&page=$page" | |
log "Fetching URL: $url" | |
curl -sSLH "Authorization: Bearer $token" "$url" | |
} | |
clone() { | |
declare -ri page=${1:-1} | |
if (( page > 1 )); then | |
read -r count | |
if [[ "$count" == 0 ]]; then return; fi | |
while IFS=, read -r id url key; do | |
dst="$dst_dir/$key-$id" | |
if [[ -d "$dst" ]]; then | |
if (( sync )); then | |
log "Gist already cloned; updating: $dst" | |
git -C "$dst" pull | |
else | |
log "Skipping already cloned gist: $dst" | |
fi | |
else | |
log "Cloning gist: $url → $dst" | |
if (( use_ssh )); then | |
git clone "[email protected]:$id.git" "$dst" | |
else | |
git clone "$url" "$dst" | |
fi | |
fi | |
done | |
fi | |
gists "$page" \ | |
| jq -r 'length, (.[] | [.id, .git_pull_url, (.files | to_entries[0].key)] | join(","))' \ | |
| clone $(( page + 1 )) | |
} | |
main() { | |
for cmd in "${dependencies[@]}"; do | |
if ! command -v "$cmd" &> /dev/null; then | |
log "error: $cmd command is missing" | |
exit 1 | |
fi | |
done | |
log "Cloning gists into: $dst_dir/" | |
mkdir -p "$dst_dir" | |
clone | |
} | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment