github.com/yrj2011/jx-test-infra@v0.0.0-20190529031832-7a2065ee98eb/experiment/find-merge-conflicts.sh (about)

     1  #!/usr/bin/env bash
     2  # Copyright 2017 The Kubernetes Authors.
     3  #
     4  # Licensed under the Apache License, Version 2.0 (the "License");
     5  # you may not use this file except in compliance with the License.
     6  # You may obtain a copy of the License at
     7  #
     8  #     http://www.apache.org/licenses/LICENSE-2.0
     9  #
    10  # Unless required by applicable law or agreed to in writing, software
    11  # distributed under the License is distributed on an "AS IS" BASIS,
    12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  # Usage: GITHUB_TOKEN=<api token> find-merge-conflicts.sh <ORG> <REPO>
    17  #
    18  # This script uses the GitHub API to find all open unmergable PRs (i.e. those
    19  # with merge conflicts), then checks out the corresponding git repository and
    20  # attempts to merge the PRs, printing conflicts to stdout.
    21  #
    22  # Status messages are printed to stderr with a hash (#) as prefix.
    23  # Each PR is identified to stdout by a message prefixed with an asterisk (*).
    24  # This makes it easy to process the results: stdout contains just the PRs and
    25  # conflicts, and the PRs can be filtered out with "grep -v '^*'".
    26  #
    27  # For example, to save conflicts and a summarized tally:
    28  #   GITHUB_TOKEN=<token> find-merge-conflicts.sh <ORG> <REPO> >conflicts.txt
    29  #   grep -v '^*' conflicts.txt | sort | uniq -c | sort -rn >summary.txt
    30  
    31  set -o errexit
    32  set -o nounset
    33  set -o pipefail
    34  
    35  if [[ $# < 2 ]]; then
    36    echo "Usage: $0 <ORG> <REPO>" >&2
    37    exit 1
    38  fi
    39  
    40  if [[ -z "${GITHUB_TOKEN:-}" ]]; then
    41    echo "GITHUB_TOKEN must be set." >&2
    42    exit 1
    43  fi
    44  
    45  readonly ORG=$1
    46  readonly REPO=$2
    47  readonly GHCURL=(curl -sfSLH "Authorization: token ${GITHUB_TOKEN}")
    48  
    49  echo "# Searching for PRs with conflicts in ${ORG}/${REPO}" >&2
    50  conflicting_prs=()
    51  
    52  # This is pretty hacky.
    53  page=0
    54  while true; do
    55    page=$((page + 1))
    56    # Select only PRs that have not been tagged as stale or rotten.
    57    open_prs=$("${GHCURL[@]}" "https://api.github.com/repos/${ORG}/${REPO}/pulls?base=master&per_page=100&page=${page}" |\
    58      jq -r '.[] | select(.labels | map(.name != "lifecycle/stale" and .name != "lifecycle/rotten") | all) | .number')
    59    [[ -z "${open_prs}" ]] && break
    60    for pr in ${open_prs}; do
    61      mergeable=$("${GHCURL[@]}" -sfSL "https://api.github.com/repos/${ORG}/${REPO}/pulls/${pr}" | jq -r '.mergeable')
    62      if [[ "${mergeable}" == "false" ]]; then
    63        conflicting_prs+=("${pr}")
    64      fi
    65    done
    66  done
    67  
    68  if [[ -z "${conflicting_prs[@]:-}" ]]; then
    69    echo "# No PRs with conflicts found." >&2
    70    exit
    71  fi
    72  
    73  echo "# ${#conflicting_prs[@]} conflicting PRs found" >&2
    74  
    75  tmpdir=$(mktemp -d)
    76  trap "rm -rf ${tmpdir}" EXIT
    77  
    78  echo "# Cloning git repo ${ORG}/${REPO}" >&2
    79  git clone -q "https://github.com/${ORG}/${REPO}" "${tmpdir}"
    80  cd "${tmpdir}"
    81  git config merge.renameLimit 999999
    82  
    83  echo "# Reporting conflicts" >&2
    84  for pr in ${conflicting_prs[@]}; do
    85    # Create a branch to attempt the merge
    86    git branch -q merge-test master
    87    # Checkout that branch
    88    git checkout -q merge-test
    89    # Fetch the PR head
    90    echo "# Fetching refs/pull/${pr}/head" >&2
    91    git fetch -q -f origin "refs/pull/${pr}/head"
    92    # Merge it
    93    git merge --ff FETCH_HEAD --strategy resolve >/dev/null 2>/dev/null || true
    94    echo "* ${ORG}/${REPO}/pull/${pr}:"
    95    # Report files that are conflicting
    96    PAGER=cat git diff --name-only --diff-filter=UXB
    97    # Abort so we can reset
    98    git merge --abort >/dev/null 2>/dev/null || true
    99    git reset -q --hard
   100    git checkout -q master
   101    git branch -q -D merge-test
   102    git prune 2>/dev/null
   103  done