Skip to content

Instantly share code, notes, and snippets.

@timfallmk
Last active August 12, 2016 22:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timfallmk/6da3a330ea97c036e58b06d630cd5e16 to your computer and use it in GitHub Desktop.
Save timfallmk/6da3a330ea97c036e58b06d630cd5e16 to your computer and use it in GitHub Desktop.
GitHub API in Bash exercise

GitHub Network Graph

Purpose

This script mimics the "Network Graph" display on GitHub.com in that it fetches the number of forks of a given repo and displays the distance (commits ahead or behind) it is from the upstream repository (the repository it is forked from).

Design

The script is intended to be simple and as modular as possible without using outside dependencies. It is of course mostly a thought experiment as doing this kind of thing in bash is a bit insane.

There a few main components:

  • Two functions called get_fork_user and get_fork_branch take in a single argument (the index of a forked repo from the list generated by a later command) and returns the user and default branch of that fork, respectively
  • The main function, called fork_status takes no arguments and iterates through the returned list of forks, getting the number of commits ahead or behind it is from master. It uses get_fork_user and get_fork_branch to set variables appropriately for each run of the loop

The script also includes some basic dependency checking, including jq to process JSON payloads returned by the GitHub API. It would be absolutely rediculous to rewrite a JSON parser in Bash.

The current version does not conform to design guidelines and is a bit "messy". If this were not an excercise it would need clean up, but this demonstrates the intended purpose.

Usage

To use the script simple call it with the user/repo as the first and second parameters. For exmaple, if you wanted to run it on Mesosphere/mesos:

fork_map
User:mesosphere
Repo:mesos

TODO

  • Compare non default branches
  • Visual output
  • Validate input
  • Print usage upon invalidated input
  • World peace
#!/bin/bash
#set -ex
set -o pipefail
UPSTREAM_MASTER_BRANCH=master
UPSTREAM_MASTER_USER=default
UPSTREAM_MASTER_REPO=default
FORK_USER=test
FORK_BRANCH=master
FORK_COUNT=0
CURRENT_REPO="$(get_fork_user ${n}):$(get_fork_branch ${n})"
API_BASE_URL=https://api.github.com
# Take user input. This could be smoothed out.
echo "Input the user/repo combination you would like to check:"
read -p "User: " UPSTREAM_MASTER_USER
read -p "Repo: " UPSTREAM_MASTER_REPO
echo "Checking $UPSTREAM_MASTER_USER:$UPSTREAM_MASTER_REPO:$UPSTREAM_MASTER_BRANCH..."
# Gets some environment tests out of the way
# Check for curl
if type -P curl 2>/dev/null; then
echo "curl appears to be installed"
else
echo "curl not installed, aborting for now."
exit
fi
# Check for `jq`. Should be present. Will handle failure later
if type -P jq 2>/dev/null; then
echo "jq appears to be installed"
else
echo "jq not installed, aborting for now."
exit
fi
# Can we reach the GitHub API?
if $(curl --silent --fail https://api.github.com 1>/dev/null); then
echo "Successfully reached GitHub API"
else
echo "Could not reach GitHub API. Are you connected to the internet?"
exit
fi
# Given a specific fork, return the name of the user
get_fork_user () {
curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/forks | jq -r ".["$1"].owner.login"
}
# Given a specific fork, return the the default branch
get_fork_branch () {
curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/forks | jq -r ".["$1"].default_branch"
}
# Get a list of forks of a given repo and whether its behind or ahead
fork_status () {
FORK_COUNT=$(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/forks | jq -r ". | length")
for n in $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/forks | jq -r ".|keys[]")
do
CURRENT_REPO="$(get_fork_user ${n}):$(get_fork_branch ${n})"
echo "$(get_fork_user ${n}):$(get_fork_branch ${n})"
if [[ $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".status") = "ahead" ]]; then
echo "is ahead by $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".ahead_by")"
elif [[ $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".status") = "behind" ]]; then
echo "is behind by $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".behind_by")"
else
echo "$(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".status"): \
behind: $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".behind_by"), \
ahead: $(curl --silent --fail $API_BASE_URL/repos/$UPSTREAM_MASTER_USER/$UPSTREAM_MASTER_REPO/compare/$UPSTREAM_MASTER_BRANCH...$CURRENT_REPO | jq -r ".ahead_by")"
fi
done
}
fork_status
echo "Forks: ${FORK_COUNT}. Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment