Last active
September 12, 2015 14:25
-
-
Save obradovic/306e58049cab5b8a4b40 to your computer and use it in GitHub Desktop.
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
#!/bin/bash | |
# | |
# README | |
# On OSX please do first: | |
# brew install coreutils jq | |
# export GITHUB_ORG="fooproject" | |
# export GITHUB_REPOS="foo bar baz" | |
# export GITHUB_USER="your username" | |
# export GITHUB_PASS="your password" | |
# | |
# TODO: | |
# How long between last commit and release to production? (look at tags) | |
# Ignore WIP tags/titles | |
# | |
# Sentiment analysis on comments | |
# Handle Github's API Rate Limiting better | |
# | |
# Our Github org and list of repos | |
ORG=$GITHUB_ORG | |
# Can pass in a list of repos as arg 1. Otherwise, will just do all of them | |
REPOS=( $1 ) | |
if [ -z "$1" ] | |
then | |
REPOS=( $GITHUB_REPOS ) | |
fi | |
# just some DRYness | |
CURL="curl -s" | |
AUTH="--user $GITHUB_USER:$GITHUB_PASS" | |
GITHUB="$CURL $AUTH https://api.github.com" | |
# Iterate over the repos | |
for REPO in "${REPOS[@]}" | |
do | |
LATEST_PR=$2 | |
# If LATEST_PR was not specified on the cmd line, find the latest pr | |
if [ -z "$2" ] | |
then | |
# What is the most recent PR for this repo? | |
LATEST_PR=`$GITHUB/repos/$ORG/$REPO/pulls?state=all | jq ".[0].number"` | |
# Sanity check - maybe we got an empty response? If there hasnt been any PRs | |
if [ `echo $LATEST_PR | jq 'length'` -eq 0 ] | |
then | |
continue | |
fi | |
fi | |
# Now iterate over all PRs for this repo, starting at the most recent and then decrementing | |
for ((PR_ID=$LATEST_PR; PR_ID>=1; PR_ID--)) | |
do | |
# get the details of this PR | |
PR=`$GITHUB/repos/$ORG/$REPO/pulls/$PR_ID | jq "."` | |
# Sanity check - maybe we had an error? | |
if [[ `echo $PR | jq ".message"` = "\"Not Found\"" ]] | |
then | |
echo "$REPO PR $PR_ID not found" | |
continue | |
fi | |
# get create and update times | |
STATE=`echo $PR | jq ".state" | tr -d '"'` | |
CREATED_SECS=`echo $PR | jq ".created_at" | xargs gdate +%s -d` | |
UPDATED_SECS=`echo $PR | jq ".updated_at" | xargs gdate +%s -d` | |
# get some stats on changes | |
NUM_ADDITIONS=`echo $PR | jq ".additions"` | |
NUM_DELETIONS=`echo $PR | jq ".deletions"` | |
NUM_CHANGES=`expr $NUM_ADDITIONS + $NUM_DELETIONS` | |
NUM_CHANGED_FILES=`echo $PR | jq ".changed_files"` | |
# minor date arithmetic | |
SECS_PER_MIN=60 | |
MINS_PER_DAY=1440 | |
NOW=`gdate +%s` | |
SECS_SINCE_CREATION=`expr $NOW - $CREATED_SECS` | |
MINS_SINCE_CREATION=`expr $SECS_SINCE_CREATION / $SECS_PER_MIN` | |
DAYS_SINCE_CREATION=`expr $MINS_SINCE_CREATION / $MINS_PER_DAY` | |
# Is the PR still open? | |
if [ $STATE = "open" ]; | |
then | |
echo "$REPO PR `printf "%5s" $PR_ID` is open: `printf "%3s" $DAYS_SINCE_CREATION` days: `printf "%6s" $MINS_SINCE_CREATION` minutes" | |
continue | |
fi | |
# Was the PR closed but not merged? | |
MERGED_AT=`echo $PR | jq ".merged_at" | tr -d '"'` | |
if [ $MERGED_AT = "null" ] | |
then | |
CLOSED=`echo $PR | jq ".closed_at" | xargs gdate +%s -d` | |
SECS_TO_CLOSE=`expr $CLOSED - $CREATED_SECS` | |
MINS_TO_CLOSE=`expr $SECS_TO_CLOSE / $SECS_PER_MIN` | |
DAYS_TO_CLOSE=`expr $MINS_TO_CLOSE / $MINS_PER_DAY` | |
echo "$REPO PR `printf "%5s" $PR_ID` was closed: `printf "%3s" $DAYS_TO_CLOSE` days: `printf "%6s" $MINS_TO_CLOSE` minutes" | |
continue | |
fi | |
# ok the PR was merged. Munge! | |
MERGED_SECS=`gdate -d $MERGED_AT +%s` | |
SECS_TO_MERGE=`expr $MERGED_SECS - $CREATED_SECS` | |
MINS_TO_MERGE=`expr $SECS_TO_MERGE / $SECS_PER_MIN` | |
DAYS_TO_MERGE=`expr $MINS_TO_MERGE / $MINS_PER_DAY` | |
# VSCO time periods | |
VSCO_EPOCH="2013-04-01" | |
VSCO_YEAR=$(expr `gdate -d $MERGED_AT +%Y` - `gdate -d $VSCO_EPOCH +%Y`) | |
VSCO_MONTH=$(expr $VSCO_YEAR \* 12 + `gdate -d $MERGED_AT +%m`) | |
VSCO_DAY=$(expr $VSCO_YEAR \* 365 + `gdate -d $MERGED_AT +%j`) | |
VSCO_WEEK=$(expr $VSCO_DAY / 7 ) | |
# Get creator and merger | |
CREATOR=`echo $PR | jq ".user.login" | tr -d '"'` | |
MERGER=`echo $PR | jq ".merged_by.login" | tr -d '"'` | |
# | |
# ITERATE over the COMMITS | |
# | |
COMMITS=`$GITHUB/repos/$ORG/$REPO/pulls/$PR_ID/commits` | |
NUM_COMMITS=`echo $COMMITS | jq 'length'` | |
# Initially, set the first commit to be both the first and last date | |
FIRST_COMMIT_SECS=`echo $COMMITS | jq '.[0].commit.author.date' | tr -d '"' | xargs gdate +%s -d` | |
LAST_COMMIT_SECS=$FIRST_COMMIT_SECS | |
# start iterating at 1 instead of 0, cause we just looked at the first one | |
for ((COMMIT_ID = 1; COMMIT_ID < $NUM_COMMITS; COMMIT_ID++)) | |
do | |
COMMIT=`echo $COMMITS | jq ".[$COMMIT_ID]"` | |
AUTHOR_SECS=`echo $COMMIT | jq ".commit.author.date" | tr -d '"' | xargs gdate +%s -d` | |
if (( "$AUTHOR_SECS" < "$FIRST_COMMIT_SECS" )) | |
then | |
FIRST_COMMIT_SECS=$AUTHOR_SECS | |
fi | |
if (( "$AUTHOR_SECS" > "$LAST_COMMIT_SECS" )) | |
then | |
LAST_COMMIT_SECS=$AUTHOR_SECS | |
fi | |
done | |
# | |
# ITERATE over the COMMENTS | |
# | |
# GET: Time from first commit to first comment | |
# AND: Time from last commit to final merge | |
COMMENTS=`$GITHUB/repos/$ORG/$REPO/issues/$PR_ID/comments` # do not reference a portion of the unified diff | |
REVIEW_COMMENTS=`$GITHUB/repos/$ORG/$REPO/pulls/$PR_ID/comments` # Review Comments are comments on a portion of the unified diff | |
TOTAL_COMMENTS=`echo $COMMENTS $REVIEW_COMMENTS | jq -s add` # jams the above two jsons arrays into one | |
NUM_COMMENTS_TOTAL=`echo $TOTAL_COMMENTS | jq 'length'` | |
FIRST_COMMENT_SECS=0 | |
if [ "$NUM_COMMENTS_TOTAL" -gt 0 ]; | |
then | |
FIRST_COMMENT_SECS=`echo $TOTAL_COMMENTS | jq '.[0].created_at' | tr -d '"' | xargs gdate +%s -d` | |
fi | |
LAST_COMMENT_SECS=$FIRST_COMMENT_SECS | |
# start iterating at 1 instead of 0, cause we just looked at the first one | |
for ((COMMENT_ID = 1; COMMENT_ID < $NUM_COMMENTS_TOTAL; COMMENT_ID++)) | |
do | |
COMMENT=`echo $TOTAL_COMMENTS | jq ".[$COMMENT_ID]"` | |
COMMENT_SECS=`echo $COMMENT | jq ".created_at" | tr -d '"' | xargs gdate +%s -d` | |
if (( "$COMMENT_SECS" < "$FIRST_COMMENT_SECS" )) | |
then | |
FIRST_COMMENT_SECS=$COMMENT_SECS | |
fi | |
if (( "$COMMENT_SECS" > "$LAST_COMMENT_SECS" )) | |
then | |
LAST_COMMENT_SECS=$COMMENT_SECS | |
fi | |
done | |
# time between PR creation and first comment ("eyes on code") | |
PR_CREATE_TO_FIRST_COMMMENT_SECS=`expr $FIRST_COMMENT_SECS - $CREATED_SECS` | |
PR_CREATE_TO_FIRST_COMMMENT_MINS=`expr $PR_CREATE_TO_FIRST_COMMMENT_SECS / $SECS_PER_MIN` | |
# If there were no comments, lets write out "none" | |
if [ "$NUM_COMMENTS_TOTAL" -eq 0 ]; | |
then | |
PR_CREATE_TO_FIRST_COMMMENT_MINS="none" | |
fi | |
# time between last commit and merge ("inventory") | |
INVENTORY_SECS=`expr $MERGED_SECS - $LAST_COMMIT_SECS` | |
INVENTORY_MINS=`expr $INVENTORY_SECS / $SECS_PER_MIN` | |
echo "$REPO PR `printf "%5s" $PR_ID` was merged `printf "%3s" $DAYS_TO_MERGE` days: `printf "%6s" $MINS_TO_MERGE` minutes: `printf "%3s" $NUM_CHANGED_FILES` files had `printf "%6s" $NUM_CHANGES` changes: `printf "%3s" $NUM_COMMITS` commits with `printf "%3s" $NUM_COMMENTS_TOTAL` comments. Epoch day $VSCO_DAY week $VSCO_WEEK month $VSCO_MONTH: `printf "%6s" $PR_CREATE_TO_FIRST_COMMMENT_MINS` mins_to_comment, `printf "%6s" $INVENTORY_MINS` mins_inv: $CREATOR $MERGER" | |
done | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment