Last active
September 11, 2023 13:57
-
-
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.
This file contains hidden or 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 | |
# | |
# | |
# 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