Files
scylladb/scripts/pull_github_pr.sh
Yaron Kaikov fac682df7e [script/pull_github_pr.sh] Check Gating status before merging
Maintainers use scripts/pull_github_pr.sh from scylladb.git when merging PRs and before pushing to the next. We want to prevent merges from piling up on top of unstable builds. This change will check Gating's current status and notify the maintainers

Related to scylladb/scylla-pkg#3644

Closes scylladb/scylladb#20742
2024-09-26 08:44:06 +03:00

155 lines
5.1 KiB
Bash
Executable File

#!/bin/bash
# Script for pulling a github pull request
# along with generating a merge commit message.
# Example usage for pull request #6007 and /next branch:
# git fetch
# git checkout origin/next
# ./scripts/pull_github_pr.sh 6007
set -e
gh_hosts=~/.config/gh/hosts.yml
jenkins_url="https://jenkins.scylladb.com"
FORCE=$2
ORANGE='\033[0;33m'
NC='\033[0m'
if [[ ( -z "$GITHUB_LOGIN" || -z "$GITHUB_TOKEN" ) && -f "$gh_hosts" ]]; then
GITHUB_LOGIN=$(awk '/user:/ { print $2 }' "$gh_hosts")
GITHUB_TOKEN=$(awk '/oauth_token:/ { print $2 }' "$gh_hosts")
fi
if [[ -z "$JENKINS_USERNAME" || -z "$JENKINS_API_TOKEN" ]]; then
echo "
JENKINS_USERNAME or JENKINS_API_TOKEN is missing from env.
To create a TOKEN, browse to https://jenkins.scylladb.com, then click on your username (upper right corner) and configure. Click on Add new token and set the JENKINS_USERNAME and JENKINS_API_TOKEN environment variables accordingly.
"
exit 1
fi
if [ -z "$1" ]; then
echo Please provide a github pull request number
exit 1
fi
for required in jq curl; do
if ! type $required >& /dev/null; then
echo Please install $required first
exit 1
fi
done
curl() {
local opts=()
if [[ -n "$GITHUB_LOGIN" && -n "$GITHUB_TOKEN" ]]; then
opts+=(--user "${GITHUB_LOGIN}:${GITHUB_TOKEN}")
fi
command curl "${opts[@]}" "$@"
}
set_jenkins_job() {
branch=$(git rev-parse --abbrev-ref HEAD)
version="${branch#next-}"
product=$(awk -F'=' '/^PRODUCT/ {print $2}' <SCYLLA-VERSION-GEN)
case "$product" in
scylla) folder_prefix="scylla";;
scylla-enterprise) folder_prefix="enterprise";;
esac
case "$branch" in
next) jenkins_job="scylla-master/job/next";;
next-enterprise) jenkins_job="scylla-enterprise/job/next";;
next*) jenkins_job="$folder_prefix-$version/job/next";;
esac
}
check_jenkins_job_status() {
set_jenkins_job
lastCompletedJobName="$jenkins_url/job/$jenkins_job/lastCompletedBuild"
lastCompletedBuild="$lastCompletedJobName/api/json?tree=result"
getBuildResult=$(curl -s --user $JENKINS_USERNAME:$JENKINS_API_TOKEN $lastCompletedBuild/api/json?tree=result)
if [[ "$getBuildResult" == "*Unauthorized*" ]]; then
echo -e "${ORANGE}WARNING:${NC} Failed to authenticate with Jenkins. please check your JENKINS_USERNAME and JENKINS_API_TOKEN setting"
exit 1
fi
lastCompleted=$(curl -s --user $JENKINS_USERNAME:$JENKINS_API_TOKEN $lastCompletedBuild | jq -r '.result')
if [[ "$lastCompleted" == "SUCCESS" ]]; then
echo "$lastCompletedJobName is stable"
else
echo -e "${ORANGE}WARNING:${NC} $lastCompletedJobName is not stable"
if [[ "$FORCE" != "--force" ]]; then
echo "exiting script since $lastCompletedJobName is unstable, you can force it by running ./script/pull_github_pr.sh <pr num> --force"
exit 1
fi
fi
}
check_jenkins_job_status
NL=$'\n'
PR_NUM=$1
# convert full repo URL to its project/repo part, in case of failure default to origin/master:
REMOTE_SLASH_BRANCH="$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream} \
|| git rev-parse --abbrev-ref --symbolic-full-name master@{upstream} \
|| echo 'origin/master')"
REMOTE="${REMOTE_SLASH_BRANCH%/*}"
REMOTE_URL="$(git config --get "remote.$REMOTE.url")"
PROJECT=`sed 's/git@github.com://;s#https://github.com/##;s/\.git$//;' <<<"${REMOTE_URL}"`
PR_PREFIX=https://api.github.com/repos/$PROJECT/pulls
echo "Fetching info on PR #$PR_NUM... "
PR_DATA=$(curl -s $PR_PREFIX/$PR_NUM)
MESSAGE=$(jq -r .message <<< $PR_DATA)
if [ "$MESSAGE" != null ]
then
# Error message, probably "Not Found".
echo "$MESSAGE"
exit 1
fi
PR_TITLE=$(jq -r .title <<< $PR_DATA)
echo " $PR_TITLE"
PR_DESCR=$(jq -r .body <<< $PR_DATA)
PR_LOGIN=$(jq -r .head.user.login <<< $PR_DATA)
echo -n "Fetching full name of author $PR_LOGIN... "
USER_NAME=$(curl -s "https://api.github.com/users/$PR_LOGIN" | jq -r .name)
echo "$USER_NAME"
git fetch "$REMOTE" pull/$PR_NUM/head
nr_commits=$(git log --pretty=oneline HEAD..FETCH_HEAD | wc -l)
closes="${NL}${NL}Closes ${PROJECT}#${PR_NUM}${NL}"
if [[ $nr_commits == 1 ]]; then
commit=$(git log --pretty=oneline HEAD..FETCH_HEAD | awk '{print $1}')
message="$(git log -1 "$commit" --format="format:%s%n%n%b")"
if ! git cherry-pick $commit
then
echo "Cherry-pick failed. You are now in a subshell. Either resolve with git cherry-pick --continue or git cherry-pick --abort, then exit the subshell"
head_before=$(git rev-parse HEAD)
bash
head_after=$(git rev-parse HEAD)
if [[ "$head_before" = "$head_after" ]]; then
exit 1
fi
fi
git commit --amend -m "${message}${closes}"
else
git merge --no-ff --log=1000 FETCH_HEAD -m "Merge '$PR_TITLE' from $USER_NAME" -m "${PR_DESCR}${closes}"
fi
git commit --amend # for a manual double-check
# Check PR tests status
PR_HEAD_SHA=$(jq -r .head.sha <<< $PR_DATA)
PR_TESTS_STATUS=$(curl -s "https://api.github.com/repos/$PROJECT/commits/$PR_HEAD_SHA/status" | jq -r .state)
if [ "$PR_TESTS_STATUS" != "success" ]; then
ORANGE='\033[0;33m'
NC='\033[0m'
echo -e "${ORANGE}\nWARNING:${NC} Some of the tests that ran for this PR were not completed successfully,\n" \
"please make sure all tests are done successfully before merge this PR.\n"
fi