mirror of https://github.com/Icinga/L10n.git
bin/autoresolve: Either resolve local HEAD or given pull request
This commit is contained in:
parent
3e3f0a294b
commit
89a7b0517e
210
bin/autoresolve
210
bin/autoresolve
|
@ -3,45 +3,31 @@
|
|||
# First some definitions and functions
|
||||
|
||||
: "${ICINGABOT_TOKEN:=}"
|
||||
: "${PULL_REQUEST_NO:=}"
|
||||
|
||||
RE_IS_CONFLICTING="^UU (.*)"
|
||||
RE_IS_SOURCE_CATALOG="^UU src/([a-z]{2}_[A-Z]{2})/LC_MESSAGES/icinga.po"
|
||||
RE_LABEL="automatic conflict resolution \(UTC([-+][0-9])?\)"
|
||||
|
||||
PR_QUERY=$(sed ':a;N;$!ba;s/\n/\\n/g' << GRAPHQL
|
||||
query {
|
||||
repository(owner:\"Icinga\", name:\"L10n\") {
|
||||
pullRequests(first: 100, states: OPEN) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
number
|
||||
author {
|
||||
login
|
||||
}
|
||||
mergeable
|
||||
maintainerCanModify
|
||||
headRefName
|
||||
headRepository {
|
||||
sshUrl
|
||||
}
|
||||
comments(first: 100) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
author {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
labels(first: 100) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
}
|
||||
query (\$number: Int!) {
|
||||
repository(owner:\"Icinga\", name:\"L10n\") {
|
||||
pullRequest(number: \$number) {
|
||||
id
|
||||
author {
|
||||
login
|
||||
}
|
||||
mergeable
|
||||
maintainerCanModify
|
||||
headRefName
|
||||
headRepository {
|
||||
sshUrl
|
||||
}
|
||||
comments(first: 100) {
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
author {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +37,11 @@ query {
|
|||
}
|
||||
GRAPHQL
|
||||
)
|
||||
get_open_pull_requests() {
|
||||
curl -sH "Authorization: bearer $ICINGABOT_TOKEN" -d "{\"query\": \"$PR_QUERY\"}" https://api.github.com/graphql
|
||||
get_pull_request() {
|
||||
local pull_request_no="$1"
|
||||
local data="{\"query\": \"$PR_QUERY\", \"variables\": {\"number\": $pull_request_no}}"
|
||||
|
||||
curl -sH "Authorization: bearer $ICINGABOT_TOKEN" -d "$data" https://api.github.com/graphql
|
||||
}
|
||||
|
||||
FRIENDLY_REMINDER=$(sed ':a;N;$!ba;s/\n/\\n/g' << TEXT
|
||||
|
@ -115,80 +104,40 @@ read_json_blob() {
|
|||
|
||||
echo $json | jq $varpath
|
||||
}
|
||||
should_get_resolved() {
|
||||
local offset="$1"
|
||||
|
||||
if [ -z "$offset" ]; then
|
||||
offset="UTC"
|
||||
else
|
||||
case "${offset:0:1}" in
|
||||
"-")
|
||||
offset="UTC+${offset:1:2}"
|
||||
;;
|
||||
"+")
|
||||
offset="UTC-${offset:1:2}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
hour=$(TZ=$offset date +%H)
|
||||
[[ "$hour" == "00" ]]
|
||||
return
|
||||
}
|
||||
|
||||
# Actual script starts here
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$ICINGABOT_TOKEN" ]; then
|
||||
echo "Environment variable ICINGABOT_TOKEN not set"
|
||||
exit 1
|
||||
fi
|
||||
manage_remote=true
|
||||
if [ -n "$PULL_REQUEST_NO" ]; then
|
||||
if [ -z "$ICINGABOT_TOKEN" ]; then
|
||||
echo "Environment variable ICINGABOT_TOKEN not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OPEN_PRS=$(get_open_pull_requests)
|
||||
PULL_REQUESTS=$(read_json_blob "$OPEN_PRS" .data.repository.pullRequests.edges)
|
||||
PR_NUMBER="$PULL_REQUEST_NO"
|
||||
PR_DATA="$(get_pull_request $PR_NUMBER)"
|
||||
PULL_REQUEST=$(read_json_blob "$PR_DATA" .data.repository.pullRequest)
|
||||
|
||||
TOTAL_PULL_REQUESTS=$(read_json_var "$OPEN_PRS" .data.repository.pullRequests.totalCount)
|
||||
for (( i = 0; i < $TOTAL_PULL_REQUESTS; i++ )); do
|
||||
PR_NUMBER=$(read_json_var "$PULL_REQUESTS" .[$i].node.number)
|
||||
|
||||
PR_MERGEABLE=$(read_json_var "$PULL_REQUESTS" .[$i].node.mergeable)
|
||||
PR_MERGEABLE=$(read_json_var "$PULL_REQUEST" .mergeable)
|
||||
if [[ "$PR_MERGEABLE" != "CONFLICTING" ]] && [[ "$PR_MERGEABLE" != "UNKNOWN" ]]; then
|
||||
echo "Ignoring pull request #$PR_NUMBER. No conflicts detected"
|
||||
continue
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Attempting to resolve pull request #$PR_NUMBER..."
|
||||
|
||||
# Pull requests only get automatically resolved if they have an appropriate label
|
||||
SHOULD_GET_RESOLVED=false
|
||||
TOTAL_LABELS=$(read_json_var "$PULL_REQUESTS" .[$i].node.labels.totalCount)
|
||||
for (( j = 0; j < $TOTAL_LABELS; j++ )); do
|
||||
LABEL=$(read_json_var "$PULL_REQUESTS" .[$i].node.labels.edges[$j].node.name)
|
||||
if [[ "$LABEL" =~ $RE_LABEL ]] && [[ ${BASH_REMATCH[0]} ]]; then
|
||||
echo "Identified label '$LABEL'. Checking schedule..."
|
||||
if should_get_resolved "${BASH_REMATCH[1]}"; then
|
||||
SHOULD_GET_RESOLVED=true
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
PR_ID=$(read_json_var "$PULL_REQUEST" .id)
|
||||
|
||||
if [[ "$SHOULD_GET_RESOLVED" == "false" ]]; then
|
||||
echo "Ignoring pull request #$PR_NUMBER. No label found or it's not scheduled for now"
|
||||
continue
|
||||
fi
|
||||
|
||||
PR_ID=$(read_json_var "$PULL_REQUESTS" .[$i].node.id)
|
||||
|
||||
# If however the author disabled maintainer edits, tell him this once
|
||||
PR_IS_ACCESSIBLE=$(read_json_var "$PULL_REQUESTS" .[$i].node.maintainerCanModify)
|
||||
# If the author disabled maintainer edits, tell him this once
|
||||
PR_IS_ACCESSIBLE=$(read_json_var "$PULL_REQUEST" .maintainerCanModify)
|
||||
if [[ "$PR_IS_ACCESSIBLE" == "false" ]]; then
|
||||
ICINGABOT_COMMENTED=false
|
||||
|
||||
TOTAL_COMMENTS=$(read_json_var "$PULL_REQUESTS" .[$i].node.comments.totalCount)
|
||||
for (( j = 0; j < $TOTAL_COMMENTS; j++ )); do
|
||||
COMMENT_AUTHOR=$(read_json_var "$PULL_REQUESTS" .[$i].node.comments.edges[$j].node.author.login)
|
||||
TOTAL_COMMENTS=$(read_json_var "$PULL_REQUEST" .comments.totalCount)
|
||||
for (( i = 0; i < $TOTAL_COMMENTS; i++ )); do
|
||||
COMMENT_AUTHOR=$(read_json_var "$PULL_REQUEST" .comments.edges[$i].node.author.login)
|
||||
if [[ $COMMENT_AUTHOR != "icingabot" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
@ -202,60 +151,69 @@ for (( i = 0; i < $TOTAL_PULL_REQUESTS; i++ )); do
|
|||
fi
|
||||
|
||||
echo "Ignoring pull request #$PR_NUMBER. Maintainer edits are disallowed"
|
||||
continue
|
||||
exit
|
||||
fi
|
||||
|
||||
PR_AUTHOR=$(read_json_var "$PULL_REQUESTS" .[$i].node.author.login)
|
||||
PR_BRANCH=$(read_json_var "$PULL_REQUESTS" .[$i].node.headRefName)
|
||||
PR_REPO=$(read_json_var "$PULL_REQUESTS" .[$i].node.headRepository.sshUrl)
|
||||
PR_AUTHOR=$(read_json_var "$PULL_REQUEST" .author.login)
|
||||
PR_BRANCH=$(read_json_var "$PULL_REQUEST" .headRefName)
|
||||
PR_REPO=$(read_json_var "$PULL_REQUEST" .headRepository.sshUrl)
|
||||
|
||||
echo "Resolving pull request #$PR_NUMBER (Author: $PR_AUTHOR, Branch: $PR_BRANCH, Repo: $PR_REPO)"
|
||||
else
|
||||
echo "Attempting to resolve source catalog conflicts in local HEAD"
|
||||
manage_remote=false
|
||||
fi
|
||||
|
||||
if [ "$manage_remote" == true ]; then
|
||||
# Fetch the remote branch
|
||||
git remote add $PR_AUTHOR $PR_REPO
|
||||
git fetch $PR_AUTHOR $PR_BRANCH
|
||||
|
||||
# Checkout the branch
|
||||
git checkout -b pull/$PR_NUMBER $PR_AUTHOR/$PR_BRANCH
|
||||
fi
|
||||
|
||||
# Attempt to merge master, should fail
|
||||
git merge --no-ff --no-commit origin/master || true
|
||||
# Attempt to merge master, should fail
|
||||
git merge --no-ff --no-commit origin/master || true
|
||||
|
||||
if [ ! -f .git/MERGE_HEAD ]; then
|
||||
echo "Merge aborted or succeeded for some unknown reason. Cancelling pull request resolution"
|
||||
continue
|
||||
fi
|
||||
if [ ! -f .git/MERGE_HEAD ]; then
|
||||
echo "Merge aborted or succeeded for some unknown reason. Cancelling pull request resolution"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Resolve source catalog conflicts
|
||||
GIT_STATUS=$(git status -suno)
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ $RE_IS_CONFLICTING ]] && [[ ${BASH_REMATCH[0]} ]]; then
|
||||
# Only a conflict, yet
|
||||
FILENAME="${BASH_REMATCH[1]}"
|
||||
# Resolve source catalog conflicts
|
||||
GIT_STATUS=$(git status -suno)
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ $RE_IS_CONFLICTING ]] && [[ ${BASH_REMATCH[0]} ]]; then
|
||||
# Only a conflict, yet
|
||||
FILENAME="${BASH_REMATCH[1]}"
|
||||
|
||||
# Reset file to the author's version
|
||||
git checkout --ours $FILENAME
|
||||
# Reset file to the author's version
|
||||
git checkout --ours $FILENAME
|
||||
|
||||
if [[ "$line" =~ $RE_IS_SOURCE_CATALOG ]] && [[ ${BASH_REMATCH[0]} ]]; then
|
||||
# It's a source catalog! Utilize msgmerge to update the source catalog with the latest messages
|
||||
LOCALE="${BASH_REMATCH[1]}"
|
||||
echo "Resolving file '$FILENAME':"
|
||||
msgmerge --update --backup=none --lang=$LOCALE --sort-by-file $FILENAME src/icinga.pot
|
||||
git add $FILENAME
|
||||
else
|
||||
# It's some other file we don't care about. That's the authors duty to fix this
|
||||
git add $FILENAME
|
||||
fi
|
||||
if [[ "$line" =~ $RE_IS_SOURCE_CATALOG ]] && [[ ${BASH_REMATCH[0]} ]]; then
|
||||
# It's a source catalog! Utilize msgmerge to update the source catalog with the latest messages
|
||||
LOCALE="${BASH_REMATCH[1]}"
|
||||
echo "Resolving file '$FILENAME':"
|
||||
msgmerge --update --backup=none --lang=$LOCALE --sort-by-file $FILENAME src/icinga.pot
|
||||
git add $FILENAME
|
||||
else
|
||||
# It's some other file we don't care about. That's the authors duty to fix this
|
||||
git add $FILENAME
|
||||
fi
|
||||
done <<< "$GIT_STATUS"
|
||||
fi
|
||||
done <<< "$GIT_STATUS"
|
||||
|
||||
# Finish the merge
|
||||
echo -e "Update with base 'origin/master'\n\nResolves source catalog conflicts" > .git/MERGE_MSG
|
||||
GIT_EDITOR=true git merge --continue
|
||||
# Finish the merge
|
||||
echo -e "Update with base 'origin/master'\n\nResolves source catalog conflicts" > .git/MERGE_MSG
|
||||
GIT_EDITOR=true git merge --continue
|
||||
|
||||
if [ "$manage_remote" == true ]; then
|
||||
echo "Successfully resolved pull request #$PR_NUMBER. Pushing the changes now"
|
||||
|
||||
# Push the new changes
|
||||
git push $PR_AUTHOR pull/$PR_NUMBER:$PR_BRANCH
|
||||
send_success_message "$PR_ID"
|
||||
done
|
||||
else
|
||||
echo "Successfully resolved source catalog conflicts in local HEAD"
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue