Last active
August 17, 2024 21:52
-
-
Save skwid138/05455df21c99198c06b6b51ae5f5ffbe to your computer and use it in GitHub Desktop.
Get a list of repositories a user made commits to during a given date range. Make sure the script is executable, update GH_USERNAME and GH_TOKEN. Use `--help` for argument info.
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 | |
# Get a list of repositories the defined user made commits to in the passed in date range | |
# Example: ./gh_repo_search.sh 2018-07-01 2018-08-01 | |
# GitHub username and personal access token | |
GH_USERNAME="gh_username" | |
GH_TOKEN="***************************************" | |
# Take 2 passed in dates in yyyy-mm-dd format | |
START_DATE="" | |
END_DATE="" | |
DEBUG=false # Default is no debug output | |
# Repo Default Parameters | |
PAGE=1 | |
# Array to store the repositories the user has made commits to in the date range | |
COMMITTED_REPOS=() | |
# Store list of repo users and names to ignore | |
IGNORE_PATTERNS=() | |
# Display help information | |
display_help() { | |
echo "Usage: $0 [OPTIONS] START_DATE END_DATE" | |
echo | |
echo "This script retrieves a list of repositories the defined user made commits to during the passed-in date range." | |
echo | |
echo "Arguments:" | |
echo " START_DATE The start date for the commit search (format: yyyy-mm-dd)" | |
echo " END_DATE The end date for the commit search (format: yyyy-mm-dd)" | |
echo | |
echo "Options:" | |
echo " -d, --debug Enable debug output" | |
echo " --ignore=PATTERNS Comma-separated list of repository patterns to ignore, this accepts * as a wildcard and " | |
echo " (e.g., --ignore=\"username/repo-*, anotheruser/repo\")" | |
echo " -h, --help Display this help message and exit" | |
echo | |
echo "Examples:" | |
echo " $0 2021-12-01 2022-06-01 --ignore=\"username/repo-*, anotheruser/repo, user/*\"" | |
echo " $0 2021-12-01 2022-06-01 -d" | |
echo | |
exit 0 | |
} | |
# Make sure jq is installed | |
if ! command -v jq &>/dev/null; then | |
echo "jq is not installed. Please install it to use this script." >&2 | |
exit 1 | |
fi | |
# Parse command-line arguments | |
while [[ "$#" -gt 0 ]]; do | |
case $1 in | |
-d | --debug) | |
DEBUG=true | |
;; | |
--ignore=*) | |
# Split the patterns by comma and trim any surrounding whitespace | |
IFS=',' read -ra patterns <<<"${1#*=}" | |
for pattern in "${patterns[@]}"; do | |
pattern=$(echo "$pattern" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') | |
IGNORE_PATTERNS+=("$pattern") | |
done | |
;; | |
--ignore) | |
shift | |
IFS=',' read -ra patterns <<<"$1" | |
for pattern in "${patterns[@]}"; do | |
pattern=$(echo "$pattern" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') | |
IGNORE_PATTERNS+=("$pattern") | |
done | |
;; | |
-h | --help) | |
display_help | |
;; | |
*) | |
if [ -z "$START_DATE" ]; then | |
START_DATE="$1" | |
elif [ -z "$END_DATE" ]; then | |
END_DATE="$1" | |
fi | |
;; | |
esac | |
shift | |
done | |
# Debugging statement to ensure the arguments are parsed correctly | |
if [ "$DEBUG" = true ]; then | |
echo "Arguments parsed. Start Date: $START_DATE, End Date: $END_DATE, Ignore Patterns: ${IGNORE_PATTERNS[@]}" >&2 | |
fi | |
# Make sure the date arguments are passed in | |
if [ -z "$START_DATE" ] || [ -z "$END_DATE" ]; then | |
echo "Please provide a start date and end date in the format yyyy-mm-dd" >&2 | |
exit 1 | |
fi | |
# Get list of GitHub repos belonging to the defined user | |
get_repos() { | |
local page=$1 | |
local request_url="https://api.github.com/user/repos?per_page=100&page=${page}" | |
# Debugging statement to ensure the URL is correct | |
if [ "$DEBUG" = true ]; then | |
echo "get_repos request_url: ${request_url}" >&2 | |
fi | |
local response=$(curl -s -u "${GH_USERNAME}:${GH_TOKEN}" "${request_url}") | |
# Check if response is valid JSON before proceeding | |
if echo "$response" | jq . >/dev/null 2>&1; then | |
# Parse the response with jq to return the list of repository full_names | |
echo "$response" | jq -r '.[].full_name' | |
else | |
echo "Error: Unable to parse JSON response from GitHub API" | |
echo "$response" | |
exit 1 | |
fi | |
} | |
# Get the commits for a given repo using the passed in date range | |
get_commits() { | |
local repo=$1 | |
local start_date=$2 | |
local end_date=$3 | |
local request_url="https://api.github.com/repos/${repo}/commits?author=${GH_USERNAME}&since=${start_date}T00:00:00Z&until=${end_date}T23:59:59Z" | |
local response=$(curl -s -u "${GH_USERNAME}:${GH_TOKEN}" "${request_url}") | |
# Handle potential errors or empty repositories | |
if echo "$response" | jq . >/dev/null 2>&1; then | |
if echo "$response" | jq 'has("message") and .message == "Git Repository is empty."' >/dev/null 2>&1; then | |
if [ "$DEBUG" = true ]; then | |
echo "Repository is empty: $repo" >&2 | |
fi | |
echo "[]" # Return an empty array | |
else | |
echo "$response" | |
fi | |
else | |
echo "Error: Unable to parse JSON response for commits" | |
echo "$response" | |
exit 1 | |
fi | |
} | |
# Check if a repository should be ignored | |
should_ignore_repo() { | |
local repo_name=$1 | |
for pattern in "${IGNORE_PATTERNS[@]}"; do | |
case "$repo_name" in | |
$pattern) | |
return 0 # Repo should be ignored | |
;; | |
esac | |
done | |
return 1 # Repo should NOT be ignored | |
} | |
# Loop through each repo and get the commits for the passed in date range | |
while true; do | |
# Get list of user's repos | |
REPOS=$(get_repos $PAGE) | |
# If no repos are returned, break the loop | |
if [ -z "$REPOS" ]; then | |
[ "$DEBUG" = true ] && echo "No repositories returned or reached end of list." | |
break | |
fi | |
# Convert REPOS to an array to avoid subshell issues | |
IFS=$'\n' read -rd '' -a repo_array <<<"$REPOS" | |
# Loop through each repo in the array | |
for REPO in "${repo_array[@]}"; do | |
[ "$DEBUG" = true ] && echo "Processing repository: $REPO" | |
# Skip the repo if it matches any ignore pattern | |
if should_ignore_repo "$REPO"; then | |
[ "$DEBUG" = true ] && echo "Ignoring repository: $REPO" | |
continue | |
fi | |
# Get the commits made by the user to the repo during the passed in date range | |
COMMITS=$(get_commits "$REPO" "$START_DATE" "$END_DATE") | |
# Ensure COMMITS is valid JSON and not an error message | |
if echo "$COMMITS" | jq . >/dev/null 2>&1; then | |
commit_count=$(echo "$COMMITS" | jq length) | |
[ "$DEBUG" = true ] && echo "Commit count for $REPO: $commit_count" | |
if [ "$commit_count" -gt 0 ]; then | |
[ "$DEBUG" = true ] && echo "Adding $REPO to COMMITTED_REPOS" | |
# Add the repo full_name to the list of arrays | |
#COMMITTED_REPOS+=("$REPO") | |
COMMITTED_REPOS+=("$REPO | $commit_count") | |
else | |
[ "$DEBUG" = true ] && echo "No commits found for $REPO in the specified timeframe." | |
fi | |
else | |
echo "Error: Unable to parse JSON response for commits" | |
echo "$COMMITS" | |
exit 1 | |
fi | |
done | |
# If fewer than 100 repos are returned, break out of the loop | |
if [ "${#repo_array[@]}" -lt 100 ]; then | |
break | |
fi | |
# Bump the page number to get the next group of 100 repos for the user | |
PAGE=$((PAGE + 1)) | |
done | |
# Echo the list of repositories the user has made commits to in the date range | |
[ "$DEBUG" = true ] && echo "Final COMMITTED_REPOS content: ${COMMITTED_REPOS[@]}" | |
if [ ${#COMMITTED_REPOS[@]} -gt 0 ]; then | |
echo "Repositories ${GH_USERNAME} committed to:" | |
for REPO in "${COMMITTED_REPOS[@]}"; do | |
echo "${REPO}" | |
done | |
else | |
echo "No commits found in the specified timeframe." | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment