You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DevOps-Bash-tools/github_repos_sync_status.sh

181 lines
7.0 KiB
Bash

#!/usr/bin/env bash
# vim:ts=4:sts=4:sw=4:et
#
# Author: Hari Sekhon
# Date: 2020-08-31 18:05:24 +0100 (Mon, 31 Aug 2020)
#
# https://github.com/harisekhon/bash-tools
#
# License: see accompanying Hari Sekhon LICENSE file
#
# If you're using my code you're welcome to connect with me on LinkedIn and optionally send me feedback to help steer this or other code I publish
#
# https://www.linkedin.com/in/harisekhon
#
set -euo pipefail
[ -n "${DEBUG:-}" ] && set -x
srcdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1090
. "$srcdir/lib/utils.sh"
# shellcheck disable=SC1090
. "$srcdir/lib/github.sh"
# shellcheck disable=SC2034,SC2154
usage_description="
For each non-fork GitHub repo, checks corresponding GitLab and/or BitBucket repos to check they are in sync with the same master hashref
Useful for checking if GitLab repo mirroring has broken or if BitBucket hasn't been pushed to be kept in sync with master GitHub repos
Output Format:
Repo: <user>/<repo> GitHub: <sha_hash> GitLab: <sha_hash> BitBucket: <sha_hash> In-Sync: <boolean>
Output Format If selecting only one of --gitlab / --bitbucket:
Repo: <user>/<repo> GitHub: <sha_hash> GitLab: <sha_hash> In-Sync: <boolean>
Repo: <user>/<repo> GitHub: <sha_hash> BitBucket: <sha_hash> In-Sync: <boolean>
Arguments can be specified to check only select repos, and options can be specified to compare each GitHub repo to its
GitLab or BitBucket counterpart of the same name (by default checks both)
By default this will check through all GitHub repos - this can be pages of hundreds of lines of GitHub repos, so for
efficiency you may want to explicitly specify the repos as args or in cases where not all repos are mirrored to GitLab
or pushed to BitBucket
User name is assumed to be the same across GitHub / GitLab / BitBucket. If it's not, make sure to specify \$GITLAB_USER / \$BITBUCKET_USER to override
Caveats:
- due to a limitation of the BitBucket API requiring username + token, cannot auto-determine username so if your
\$BITBUCKET_USERNAME / \$BITBUCKET_USER / \$USER etc is incorrect, this'll fail to authenticate and won't find the relevant repo,
returning 'None' for the hashref and 'In-Sync: False'. You must ensure your BitBucket username is correct
- the BitBucket workspace is assumed to be the same as the username
"
# used by usage() in lib/utils.sh
# shellcheck disable=SC2034
usage_args="[options] [<repos_to_check>]"
# used by usage() in lib/utils.sh
# shellcheck disable=SC2034
usage_switches="
-g --gitlab Compare each GitHub repo with its GitLab counterpart
-b --bitbucket Compare each GitHub repo with its BitBucket counterpart
-d --date Compare by date of latest commit instead of hashref
-l --long-hashrefs Use long 40 char hashrefs, not 8 char abbreviated ones
"
help_usage "$@"
#min_args 1 "$@"
repos=()
check_gitlab=0
check_bitbucket=0
compare_by_date=0
long_hashrefs=0
for arg; do
case "$arg" in
-g|--gitlab) check_gitlab=1
;;
-b|--bitbucket) check_bitbucket=1
;;
-d|--date) compare_by_date=1
shift || :
;;
-l|--long-hashrefs) long_hashrefs=1
shift || :
;;
-D|--debug) export DEBUG=1
shift || :
;;
-*) usage
;;
*) repos+=("$arg")
;;
esac
done
if [ $compare_by_date = 1 ] && [ $long_hashrefs = 1 ]; then
usage "--date and --long-hashrefs are mutually exclusive"
fi
github_user="$(get_github_user)"
if is_mac; then
date(){
command gdate "$@"
}
fi
check_repos(){
for repo in "$@"; do
if [ $compare_by_date = 1 ]; then
# GitHub returns Z time
github_master_ref="$("$srcdir/github_api.sh" "/repos/$github_user/$repo/commits/master?per_page=1" | jq -r '.commit.committer.date')"
else
github_master_ref="$("$srcdir/github_api.sh" "/repos/$github_user/$repo/git/ref/heads/master" | jq -r '.object.sha')"
if [ $long_hashrefs = 0 ]; then
github_master_ref="${github_master_ref:0:8}"
fi
fi
# don't printf as we go because it's harder to debug, instead collect the line and print in one go
line="$(printf '%-26s\tGitHub: %s\t' "$github_user/$repo" "$github_master_ref")"
in_sync=True
if [ $check_gitlab = 1 ] || [ $check_bitbucket = 0 ]; then
if [ $compare_by_date = 1 ]; then
# GitHub returns current timezone eg. .000+01:00
gitlab_master_ref="$("$srcdir/gitlab_api.sh" "/projects/<user>%2F$repo/repository/commits?ref_name=master&per_page=1" 2>/dev/null | jq -r '.[0].created_at' || echo None)"
if [ "$gitlab_master_ref" != None ]; then
gitlab_master_ref="$(date --utc -d "$gitlab_master_ref" '+%FT%TZ')"
fi
else
# or .commit.short_id - only GitLab gives this short hashref in the API, we'll just truncate all of them to 8 chars for output
gitlab_master_ref="$("$srcdir/gitlab_api.sh" "/projects/<user>%2F$repo/repository/branches/master" 2>/dev/null | jq -r '.commit.id' || echo None)"
if [ $long_hashrefs = 0 ]; then
gitlab_master_ref="${gitlab_master_ref:0:8}"
fi
fi
line+="$(printf "GitLab: %-${#github_master_ref}s\t" "$gitlab_master_ref")"
if [ "$gitlab_master_ref" != "$github_master_ref" ]; then
in_sync=False
fi
fi
if [ $check_bitbucket = 1 ] || [ $check_gitlab = 0 ]; then
if [ $compare_by_date = 1 ]; then
# BitBucket returns +00:00 timezone
bitbucket_master_ref="$("$srcdir/bitbucket_api.sh" "/repositories/<user>/$repo/commits/master?pagelen=1" 2>/dev/null | jq -r '.values[0].date' || echo None)"
if [ "$bitbucket_master_ref" != None ]; then
bitbucket_master_ref="$(date --utc -d "$bitbucket_master_ref" '+%FT%TZ')"
fi
else
bitbucket_master_ref="$("$srcdir/bitbucket_api.sh" "/repositories/<user>/$repo/refs/branches/master" 2>/dev/null | jq -r '.target.hash' || echo None)"
if [ $long_hashrefs = 0 ]; then
bitbucket_master_ref="${bitbucket_master_ref:0:8}"
fi
fi
line+="$(printf "BitBucket: %-${#github_master_ref}s" "$bitbucket_master_ref")"
if [ "$bitbucket_master_ref" != "$github_master_ref" ]; then
in_sync=False
fi
fi
printf '%s\tIn-Sync: %s\n' "$line" "$in_sync"
done
}
if [ "${#repos[@]}" -gt 0 ]; then
check_repos "${repos[@]}"
else
# want splitting
# shellcheck disable=SC2046
check_repos $(get_github_repos "$github_user")
fi