The interface of Jenkins has changed, and the instructions for creating a token are out-of-date. This commit updates them. Closes scylladb/scylladb#28054
275 lines
8.0 KiB
Bash
Executable File
275 lines
8.0 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
|
|
|
|
shopt -s extglob
|
|
|
|
trap 'echo "error $? in $0 line $LINENO"' ERR
|
|
|
|
gh_hosts=~/.config/gh/hosts.yml
|
|
jenkins_url="https://jenkins.scylladb.com"
|
|
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 go to the Security tab. Click on Add new token and set the JENKINS_USERNAME and JENKINS_API_TOKEN environment variables accordingly.
|
|
"
|
|
exit 1
|
|
fi
|
|
|
|
for required in jq curl; do
|
|
if ! type $required >& /dev/null; then
|
|
echo Please install $required first
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
ALLOW_SUBMODULE=0
|
|
ALLOW_UNSTABLE=0
|
|
ALLOW_ANY_BRANCH=0
|
|
|
|
function print_usage {
|
|
cat << EOF
|
|
Usage: ${0} [options] PR_NUMBER
|
|
|
|
Script for pulling and merging a pull request.
|
|
|
|
Fetches the PR locally and merges it into current branch. The branch must be named next*.
|
|
|
|
PR with a single commit in it is cherry-picked and thus the merge commit is not created and
|
|
the PR description is lost.
|
|
|
|
By default, doesn't merge PR that contains a submodule update, use --allow-submodule option
|
|
to proceed.
|
|
|
|
Options:
|
|
|
|
-h
|
|
Print this help message and exit.
|
|
|
|
--allow-submodule
|
|
Allow a PR to update a submudule
|
|
|
|
--allow-unstable
|
|
Do not check jenkins job status
|
|
|
|
--allow-any-branch
|
|
Merge PR even if target branch is not next
|
|
|
|
--force
|
|
Sets all above --allow-* options
|
|
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]
|
|
do
|
|
case $1 in
|
|
"--force"|"-f")
|
|
ALLOW_UNSTABLE=1
|
|
ALLOW_SUBMODULE=1
|
|
ALLOW_ANY_BRANCH=1
|
|
shift 1
|
|
;;
|
|
--allow-submodule)
|
|
ALLOW_SUBMODULE=1
|
|
shift
|
|
;;
|
|
--allow-unstable)
|
|
ALLOW_UNSTABLE=1
|
|
shift
|
|
;;
|
|
--allow-any-branch)
|
|
ALLOW_ANY_BRANCH=1
|
|
shift
|
|
;;
|
|
+([0-9]))
|
|
PR_NUM=$1
|
|
shift 1
|
|
;;
|
|
"-h")
|
|
print_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "error: unrecognized option: $1, see $0 -h for usage" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$PR_NUM" ]; then
|
|
echo Please provide a github pull request number
|
|
exit 1
|
|
fi
|
|
|
|
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";;
|
|
*) echo "None supported product, valid options scylla|scylla-enterprise"
|
|
exit 1
|
|
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";;
|
|
*) echo "You are running the script from branch: $branch. Valid branches: next|next-enterprise|next-*"
|
|
exit 1
|
|
esac
|
|
}
|
|
|
|
check_jenkins_job_status() {
|
|
set_jenkins_job
|
|
|
|
lastCompletedJobName="$jenkins_url/job/$jenkins_job/lastCompletedBuild"
|
|
getBuildResult=$(curl -s --user $JENKINS_USERNAME:$JENKINS_API_TOKEN $lastCompletedJobName/api/json?tree=result)
|
|
if [[ $getBuildResult =~ (Access Denied|401 Unauthorized) ]]; then
|
|
echo -e "${ORANGE}WARNING:${NC} Access Denied to $lastCompletedJobName. \nPlease check your JENKINS_USERNAME and JENKINS_API_TOKEN setting"
|
|
exit 1
|
|
fi
|
|
|
|
lastCompleted=$(echo "$getBuildResult" | jq -r '.result')
|
|
|
|
if [[ "$lastCompleted" == "SUCCESS" ]]; then
|
|
echo "$lastCompletedJobName is stable"
|
|
else
|
|
echo -e "${ORANGE}WARNING:${NC} $lastCompletedJobName is not stable"
|
|
fi
|
|
}
|
|
|
|
if [[ $ALLOW_UNSTABLE -eq 0 ]]; then
|
|
check_jenkins_job_status
|
|
fi
|
|
|
|
NL=$'\n'
|
|
|
|
# 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 .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"
|
|
|
|
if [[ $ALLOW_ANY_BRANCH -eq 0 ]]; then
|
|
BASE_BRANCH=$(jq -r .base.ref <<< $PR_DATA)
|
|
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
TARGET_BASE="unknown"
|
|
if [[ ${BASE_BRANCH} == master ]]; then
|
|
TARGET_BASE="next"
|
|
elif [[ ${BASE_BRANCH} == branch-* ]]; then
|
|
TARGET_BASE=${BASE_BRANCH//branch/next}
|
|
fi
|
|
if [[ "${CURRENT_BRANCH}" != "${TARGET_BASE}" ]]; then
|
|
echo "Merging into wrong next, want ${TARGET_BASE}, have ${CURRENT_BRANCH}. Use --allow-any-branch or --force to skip this check"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
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 [[ "$PR_TITLE" = *submodule* ]]; then
|
|
ALLOW_SUBMODULE=1
|
|
fi
|
|
|
|
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
|
|
|
|
mapfile -t files_changed < <(git diff --name-only HEAD~1 HEAD)
|
|
mapfile -t submodules < <(git show HEAD~1:.gitmodules | sed -n 's/.*path = //p')
|
|
|
|
submodules+=(.gitmodules)
|
|
|
|
# Check if any changed files are in submodule directories
|
|
has_submodule_changes=0
|
|
for submodule in "${submodules[@]}"; do
|
|
for file in "${files_changed[@]}"; do
|
|
if [[ "$file" == "$submodule" ]]; then
|
|
has_submodule_changes=1
|
|
echo "Found submodule change: $file"
|
|
fi
|
|
done
|
|
done
|
|
|
|
if (( has_submodule_changes && ! ALLOW_SUBMODULE )); then
|
|
echo "ERROR: This pull request includes submodule changes but --allow-submodule flag was not provided"
|
|
echo "NOTE: The bad commit was left in the tree, do not push it."
|
|
exit 1
|
|
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
|