2

I was wondering how to check if a pull request has conflicts on GitHub using a script from my PC? There is a nice solution mentioned here to do it via GitHub actions: https://stackoverflow.com/a/71692270/4441211

However, taking the same script from https://olivernybroe/action-conflict-finder and running it on my PC won't work unless I do a local merge. After identifying the conflicts I would have to discard the local merge. This process seems inefficient and I was looking for a "cleaner" and faster solution.

Eyal Gerber
  • 1,026
  • 10
  • 27
  • 1
    This should be soon (Q3/Q4 2022) be easier to do with [`git merge-tree` and Git 2.38](https://stackoverflow.com/a/73091924/6309) – VonC Sep 12 '22 at 07:27

2 Answers2

5

Here is how to pipe it without a shell loop, and parse JSON natively, either with gh api -q built-in jq query, or jq itself.

#!/usr/bin/env sh

REPOSITORY_NAME=
OWNER=

gh api -H "Accept: application/vnd.github+json" \
  "repos/${OWNER}/${REPOSITORY_NAME}/pulls" --cache 1h |
  jq -j --arg curbranch "$(git rev-parse --abbrev-ref HEAD)" \
  '
.[] | select(
  (.base.ref == $curbranch) and
  (.state == "open") and
  (.draft == false)
) | .number | tostring + "\u0000"
' |
  xargs -0 -I{} \
    gh api -H "Accept: application/vnd.github+json" \
    "repos/${OWNER}/${REPOSITORY_NAME}/pulls/{}" --cache 1h \
    -q '
"PR #" + (.number | tostring) + ": " +
.title + " is " +
if .mergeable != false then "mergeable" else "not mergeable" end
'

Altenatively using a while read -r loop instead of xargs which seems problematic in some Windows environment:

gh api -H "Accept: application/vnd.github+json" \
  "repos/${OWNER}/${REPOSITORY_NAME}/pulls" --cache 1h |
  jq -r --arg curbranch "$(git rev-parse --abbrev-ref HEAD)" \
  '
.[] | select(
  (.base.ref == $curbranch) and
  (.state == "open") and
  (.draft != true)
) | .number
' | while read -r pr; do
    gh api -H "Accept: application/vnd.github+json" \
    "repos/${OWNER}/${REPOSITORY_NAME}/pulls/${pr}" --cache 1h \
    -q '
"PR #" + (.number | tostring) + ": " +
.title + " is " +
if .mergeable != false then "mergeable" else "not mergeable" end
'
done
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
  • I tried to run your script after defining the `REPOSITORY_NAME` and `OWNER` variables. Nothing happened... I hit enter and nothing.... – Eyal Gerber Sep 12 '22 at 09:00
  • I left only the `.state == "open"` in the select and I got it to do something but I keep getting an error saying `net/url: invalid control character in URL`. I can see that all the pull requests shown have a `\r` in their string in the end which is probably the cause for this. How do you remove it? – Eyal Gerber Sep 12 '22 at 11:46
  • It's a problem with xargs on windows - it adds `\r` to each line. Bottom line is that the script will not work on windows using git-bash terminal, cygwin terminal, msys terminal etc. It only works fine on wsl. So if someone wants to get it to work on one of the terminals I mentioned, they should split the script into two and not use xargs. Instead simply assign the output of the search into a variable. Then use that variable in the second part. – Eyal Gerber Sep 12 '22 at 14:36
  • 1
    @EyalGerber I added an alternative to `xargs` – Léa Gris Sep 12 '22 at 15:29
  • the do-while solution still results in a \r at the end of each result. However, to fix this you can simply add after the `do` in a new line the following `pr="${pr/$'\r'/}"` and this will resolve the issue for windows users. – Eyal Gerber Sep 13 '22 at 13:26
  • @EyalGerber then it is the issue with the broken Cygwin or other wacky version of jq deciding to use DOS line-ending in a Unix shell environment. Broken tools will always cause problems. There are ways to deal with DOS line-ending from command output but it is not very elegant. Just adds extra hoops. Get the right tools that do correct line ending for their environment is probably a more straightforward option. – Léa Gris Sep 13 '22 at 14:20
1

So I wanted to share my solution which is much "cleaner" than what I wrote in the question. I simply used GitHub API to retrieve the "mergeable" state information of the pull request. This does not require me to do any local merges and discards to search for conflict-identifying strings such as ">>>>>>>" etc.

#!/bin/bash    
OWNER="GitHub_UserName" #your github user name or organization name - whoever owns the repository
REPOSITORY_NAME="Your_Repo_Name"
PR_List=$(gh pr list) #Get list of pull requests of the repository
Current_Branch=$(git rev-parse --abbrev-ref HEAD) #get the current branch name
if [[ $(grep "$Current_Branch" <<< "$PR_List") ]]; then #If true then there exists a PR for this branch in the repository 
        #Get the line of the pull request from the list:
        PR_Line=$(grep "$Current_Branch" <<< "$PR_List")
        
        #Get the specific numerical ID of the pull request
        PR_ID=$(awk '{print $1}' <<< "$PR_Line")    #taken from https://stackoverflow.com/a/36736249/4441211

        #now get all the PR information from GitHub:
        pr_data=$(gh api -H "Accept: application/vnd.github+json" repos/$OWNER/$REPOSITORY_NAME/pulls/$PR_ID)

        #Now extract the specific "mergeable" state of the PR and then check it:
        mergeable_row=$(grep "mergeable" <<< "$pr_data")
        mergeable_string=$(echo "$mergeable_row" | awk -F 'mergeable":' '{printf $NF}')
        mergeable_state=$(echo "$mergeable_string" | cut -d',' -f 1)
        echo "Mergeable = $mergeable_state" #for debug
        if [ "$mergeable_state" == "false" ]; then
            MergeIssuesFound="yes"
            echo "Pull Request in repository $REPOSITORY_NAME is NOT mergeable"
        else
            MergeIssuesFound="no"
            echo "Pull Request in repository $REPOSITORY_NAME is mergeable"
        fi
fi
Eyal Gerber
  • 1,026
  • 10
  • 27
  • 1
    You should really switch to `jq` to parse the JSON data from the GitHub API. Also you get `PR_List=$(gh pr list)` in a string. You should consider `mapfile` it into an array. – Léa Gris Sep 12 '22 at 07:24
  • 1
    `git branch` does not have a consistent output format suitable for parsing its output. Prefer `git rev-parse --abbrev-ref HEAD` instead. – Léa Gris Sep 12 '22 at 07:26
  • 1
    @LéaGris I updated the script that gets the current branch. – Eyal Gerber Sep 13 '22 at 09:15