Skip to content

Instantly share code, notes, and snippets.

@maelvls
Last active September 11, 2023 13:57
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 maelvls/11c5f85e73fcce1ec58d287d63a308db to your computer and use it in GitHub Desktop.
Save maelvls/11c5f85e73fcce1ec58d287d63a308db to your computer and use it in GitHub Desktop.
Auto-approve GitLab merge requests when there is a "2 approvals" requirement on a repository that slows things down and needs to be worked around.
#!/bin/bash
#
#
# Copy auto-approve to the VM:
# gcloud compute ssh cronjob-gitlab-approval --zone europe-west2-b -- sudo tee /usr/local/bin/auto-approve <~/bin/auto-approve >/dev/null
#
# Then:
# gcloud compute ssh cronjob-gitlab-approval --zone europe-west2-b
# crontab -e
#
# The contents of the crontab should be something like:
# */1 * * * * auto-approve --repo REPO --when-author AUTHOR --if-approved-by SOMEONE_I_TRUST --do-it 2>&1 >> /home/mvalais/cron.log && curl -fsS --retry 3 https://cronhub.io/ping/PING_ID > /dev/null
#
set -euo pipefail
help() {
cat <<EOF
USAGE:
$(basename "$0") --repo <repo> --when-author <author> --if-approved-by <trusted_approver> [--do-it]"
EXAMPLE:
$(basename "$0") --repo venafi/vaas/applications/tls-protect/dmi/cli/firefly-ca --when-author tim.ramlot --if-approved-by richard.wall.venafi"
DESCRIPTION:
$(basename "$0") checks if the merge requests of the given author have been
approved by the given trusted approver. If that's the case, it will add your
approval to the merge request using glab's credentials.
By default, it runs in "dry mode" and doesn't actually approve the merge
requests. To actually approve them, pass the --do-it flag.
PREREQUISITES
jq, glab, gitlab credentials for glab. To install everything on Debian or
Ubuntu, run:
sudo apt update && sudo apt install -y jq
curl -LO https://gitlab.com/gitlab-org/cli/-/releases/v1.32.0/downloads/glab_1.32.0_Linux_x86_64.deb
sudo apt install -y ./glab_1.32.0_Linux_x86_64.deb
glab auth login
The GitLab token needs to have the "api" and "read_user" scopes.
EOF
}
do_it=false
while [[ $# -gt 0 ]]; do
case "$1" in
--repo)
repo=$2
shift
shift
;;
--when-author)
author=$2
shift
shift
;;
--if-approved-by)
trusted_approver=$2
shift
shift
;;
--do-it)
do_it=true
shift
;;
-h | --help)
help
exit 0
;;
*)
echo "Error: unknown argument '$1'. --help may help you."
exit 1
;;
esac
done
if [[ -z "${repo:-}" ]]; then
echo "Error: --repo is required. Example: --repo venafi/vaas/applications/tls-protect/dmi/cli/firefly-ca."
exit 1
fi
if [[ -z "${author:-}" ]]; then
echo "Error: --when-author is required. Example: --when-author tim.ramlot."
exit 1
fi
if [[ -z "${trusted_approver:-}" ]]; then
echo "Error: --if-approved-by is required. Example: --if-approved-by richard.wall.venafi."
exit 1
fi
myself_json=$(glab api "/user")
myself=$(jq -r .username <<<"$myself_json")
user_json=$(glab api "/users?username=tim.ramlot" | jq '.[0]')
if [[ "$user_json" == null ]]; then
echo "Username '$author' couldn't be found. Exiting."
exit 1
fi
repo_urlencoded=$(jq -Rr '@uri "\(.)"' <<<"$repo")
glab api "/projects/$repo_urlencoded/merge_requests?author_id=$(jq -r .id <<<"$user_json")&page=1&per_page=100&state=opened" \
| jq --compact-output '.[]' \
| while read -r mr_json; do
iid=$(jq -r .iid <<<"$mr_json")
approved_by=$(glab api "/projects/$repo_urlencoded/merge_requests/$iid/approval_state" \
| jq -r '.rules[].approved_by[].username' \
| sort \
| uniq)
if grep -q "$myself" <<<"$approved_by"; then
echo "👍 $author's merge request $iid was already approved by me. Not doing anything. MR: https://gitlab.com/$repo/-/merge_requests/$iid"
fi
approved_by=$(grep -v "$myself" <<<"$approved_by" || true)
if [[ $(wc -l <<<"$approved_by") -gt 2 ]]; then
echo "👍 $author's merge request $iid was already approved by multiple people. Not doing anything. MR: https://gitlab.com/$repo/-/merge_requests/$iid"
elif grep -q "$trusted_approver" <<<"$approved_by"; then
echo "✍️ $author's merge request $iid was already approved by $trusted_approver. Adding my approval since I trust $trusted_approver. MR: https://gitlab.com/$repo/-/merge_requests/$iid"
if [[ "$do_it" == true ]]; then
glab mr approve "$iid"
else
echo "^ Dry run, not approving."
fi
else
echo "⏳ $author's merge request $iid hasn't been approved by $trusted_approver yet. Not doing anything. MR: https://gitlab.com/$repo/-/merge_requests/$iid"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment