#!/bin/bash # 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" PR_QUERY=$(sed ':a;N;$!ba;s/\n/\\n/g' << GRAPHQL query (\$number: Int!) { repository(owner:\"Icinga\", name:\"L10n\") { pullRequest(number: \$number) { id author { login } mergeable maintainerCanModify headRefName headRepository { nameWithOwner sshUrl } comments(first: 100) { totalCount edges { node { author { login } } } } } } } 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 I would have loved to assist you with your source catalog conflicts! Though, you've disabled edits for maintainers of Icinga/L10n. :unamused: As long as you don't enable edits for us you will have to solve conflicts manually. TEXT ) FRIENDLY_REMINDER_MUTATION=$(sed ':a;N;$!ba;s/\n/\\n/g' << GRAPHQL mutation { addComment(input: {subjectId: \"\", body: \"$FRIENDLY_REMINDER\"}) { clientMutationId } } GRAPHQL ) send_friendly_reminder() { local pull_request_id="$1" local mutation=$(echo $FRIENDLY_REMINDER_MUTATION | sed "s//$pull_request_id/") local _=$( curl -sH "Authorization: bearer $ICINGABOT_TOKEN" -d "{\"query\": \"$mutation\"}" https://api.github.com/graphql ) } SUCCESS_MESSAGE=$(sed ':a;N;$!ba;s/\n/\\n/g' << TEXT I successfully solved the conflicts in your source catalog files! :partying_face: Please make sure to pull my changes before you'll continue with the translation. Otherwise you'll risk getting conflicts in your working tree with which I can't help you. TEXT ) SUCCESS_MESSAGE_MUTATION=$(sed ':a;N;$!ba;s/\n/\\n/g' << GRAPHQL mutation { addComment(input: {subjectId: \"\", body: \"$SUCCESS_MESSAGE\"}) { clientMutationId } } GRAPHQL ) send_success_message() { local pull_request_id="$1" local mutation=$(echo $SUCCESS_MESSAGE_MUTATION | sed "s//$pull_request_id/") local _=$( curl -sH "Authorization: bearer $ICINGABOT_TOKEN" -d "{\"query\": \"$mutation\"}" https://api.github.com/graphql ) } read_json_var() { local json="$1" local varpath="$2" echo $json | jq -r $varpath } read_json_blob() { local json="$1" local varpath="$2" echo $json | jq $varpath } # Actual script starts here set -e manage_remote=true if [ -n "$PULL_REQUEST_NO" ]; then if [ -z "$ICINGABOT_TOKEN" ]; then echo "Environment variable ICINGABOT_TOKEN not set" exit 1 fi PR_NUMBER="$PULL_REQUEST_NO" PR_DATA="$(get_pull_request $PR_NUMBER)" PULL_REQUEST=$(read_json_blob "$PR_DATA" .data.repository.pullRequest) 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" exit fi echo "Attempting to resolve pull request #$PR_NUMBER..." PR_ID=$(read_json_var "$PULL_REQUEST" .id) PR_REPO_NAME=$(read_json_var "$PULL_REQUEST" .headRepository.nameWithOwner) # If the author disabled maintainer edits, tell him this once PR_IS_ACCESSIBLE=$(read_json_var "$PULL_REQUEST" .maintainerCanModify) if [[ "$PR_REPO_NAME" != "Icinga/L10n" && "$PR_IS_ACCESSIBLE" == "false" ]]; then ICINGABOT_COMMENTED=false 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 ICINGABOT_COMMENTED=true break done if [ "$ICINGABOT_COMMENTED" == false ]; then send_friendly_reminder "$PR_ID" fi echo "Ignoring pull request #$PR_NUMBER. Maintainer edits are disallowed" exit fi 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 main, should fail git merge --no-ff --no-commit origin/main || true 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]}" # 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 fi done <<< "$GIT_STATUS" # Finish the merge echo -e "Update with base 'origin/main'\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" else echo "Successfully resolved source catalog conflicts in local HEAD" fi