|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# this should enforce as much of docs/TRIAGING.md as possible, run in top directory of xeps repo |
| 4 | + |
| 5 | +# usage: triage.sh $pr_number |
| 6 | +# the last two will be HEAD and `git merge-base $pr_commit master` by default if not sent in |
| 7 | + |
| 8 | +# for testing you can: |
| 9 | +# git fetch origin +refs/pull/1254/merge |
| 10 | +# git checkout FETCH_HEAD |
| 11 | +# and only send in pr_title |
| 12 | + |
| 13 | +# test cases: |
| 14 | +# multiple xeps changed: git checkout 58cec1b6fb30ccc3b44c9dff34b94f53e958c1ac; ./tools/triage.sh 'XEP-0072, XEP-0096, XEP-0214: fix xmlns in sipub examples' 58cec1b6fb30ccc3b44c9dff34b94f53e958c1ac e4d3f721c2cf9fc7ed42c3428d098b2b3be3c8ed |
| 15 | +# protoxep: git fetch origin +refs/pull/1254/merge; git checkout FETCH_HEAD; ./tools/triage.sh "ProtoXEP: Stream Limits Advertisement" |
| 16 | +# one xep changed: git fetch origin +refs/pull/1249/merge; git checkout FETCH_HEAD; ./tools/triage.sh 'XEP-0444: bla' |
| 17 | + |
| 18 | +set -euo pipefail |
| 19 | + |
| 20 | +pr_number="$1" |
| 21 | +shift |
| 22 | +pr_title="$(gh pr view "$pr_number" --json title -q .title)" |
| 23 | + |
| 24 | +pr_commit="$(gh pr view "$pr_number" --json headRefOid -q .headRefOid)" |
| 25 | +merge_base="$(git merge-base "$pr_commit" "$(gh pr view "$pr_number" --json baseRefName -q .baseRefName)")" |
| 26 | + |
| 27 | +xpath() { |
| 28 | + set -euo pipefail |
| 29 | + xmllint --nonet --noent --xpath "$2" "$1" --nowarning --dtdvalid xep.dtd |
| 30 | +} |
| 31 | + |
| 32 | +add_tag() { |
| 33 | + gh pr edit "$pr_number" --add-label "$1" |
| 34 | +} |
| 35 | + |
| 36 | +files_changed="$(git --no-pager diff --name-only "$pr_commit" "$merge_base")" |
| 37 | + |
| 38 | +set +e |
| 39 | +protoxep="$(echo "$files_changed" | grep -E '^inbox/[^.]+.xml$')" |
| 40 | +num_protoxeps=$(echo "$protoxep" | grep -v '^$' | wc -l) |
| 41 | + |
| 42 | +xeps_changed="$(echo "$files_changed" | grep -E '^xep-[0-9]{4}.xml$')" |
| 43 | +xep_likes_changed="$(echo "$files_changed" | grep -E '^xep-[^.]+.xml$')" |
| 44 | +num_xeps_changed=$(echo "$xeps_changed" | grep -v '^$' | wc -l) |
| 45 | +set -e |
| 46 | + |
| 47 | +if [ $num_protoxeps -ge 1 ] |
| 48 | +then |
| 49 | + if [ $num_xeps_changed -ne 0 ] |
| 50 | + then |
| 51 | + echo "cannot change xeps and add ProtoXEP in 1 PR" |
| 52 | + exit 1 |
| 53 | + fi |
| 54 | + # we are dealing with a protoxep here |
| 55 | + add_tag "ProtoXEP" |
| 56 | + if [ $num_protoxeps -ne 1 ] |
| 57 | + then |
| 58 | + echo "multiple ProtoXEPs cannot be created in 1 PR" |
| 59 | + exit 1 |
| 60 | + fi |
| 61 | + expected_title="ProtoXEP: $(xpath "$protoxep" '/xep/header/title/text()')" |
| 62 | + if [ "$pr_title" != "$expected_title" ] |
| 63 | + then |
| 64 | + echo "expected title '$expected_title' got title '$pr_title'" |
| 65 | + exit 1 |
| 66 | + fi |
| 67 | + add_tag "Ready to Merge" |
| 68 | + echo "manual: be sure type '$(xpath "$protoxep" '/xep/header/type/text()')' is appropriate for XEP content" |
| 69 | + exit 0 |
| 70 | +fi |
| 71 | + |
| 72 | +# we are *not* dealing with a protoxep here |
| 73 | +if [ "$xeps_changed" != "$xep_likes_changed" ] |
| 74 | +then |
| 75 | + echo "xep files created/changed but named incorrectly: $(echo "$xep_likes_changed" | tr '\n' ' ')" |
| 76 | + exit 1 |
| 77 | +fi |
| 78 | + |
| 79 | +if [ $num_xeps_changed -eq 0 ] |
| 80 | +then |
| 81 | + # some tag for this? tooling changes? |
| 82 | + echo "manual: no XEPs changed" |
| 83 | + exit 0 |
| 84 | +fi |
| 85 | + |
| 86 | +if [ $num_xeps_changed -gt 1 ] |
| 87 | +then |
| 88 | + echo "multiple XEPs changed" |
| 89 | + exit 1 |
| 90 | +fi |
| 91 | + |
| 92 | +all_approvers="" |
| 93 | +# a super approver can approve this entire PR, because they are author on all XEPs touched |
| 94 | +super_approvers="" |
| 95 | +for xep in $xeps_changed |
| 96 | +do |
| 97 | + xep_num="XEP-$(echo "$xep" | grep -Eo '[0-9]{4}')" |
| 98 | + if ! echo "$pr_title" | grep "$xep_num" &>/dev/null |
| 99 | + then |
| 100 | + echo "title did not include '$xep_num'" |
| 101 | + exit 1 |
| 102 | + fi |
| 103 | + |
| 104 | + status="$(xpath "$xep" '/xep/header/status/text()')" |
| 105 | + approvers="" |
| 106 | + if echo "$status" | grep -E '^(Experimental|Deferred)$' &>/dev/null |
| 107 | + then |
| 108 | + # Experimental or Deferred |
| 109 | + if [ "$status" == 'Deferred' ] |
| 110 | + then |
| 111 | + add_tag "Needs Editor Action" |
| 112 | + echo "move $xep_num status to Experimental before or with merge" |
| 113 | + exit 1 |
| 114 | + fi |
| 115 | + |
| 116 | + approvers="$(xpath "$xep" '/xep/header/author/email/text()' | sort -u)" |
| 117 | + else |
| 118 | + # *not* Experimental or Deferred |
| 119 | + approvers="$(xpath "$xep" '/xep/header/approver/text()' 2>/dev/null || echo 'Unknown')" |
| 120 | + fi |
| 121 | + |
| 122 | + echo "info: $xep_num status '$status' needs approvers: '$(echo "$approvers" | tr '\n' ' ' | xargs)'" |
| 123 | + |
| 124 | + new_all_approvers="$(echo -e "$all_approvers\n$approvers" | sort -u)" |
| 125 | + if [ "$all_approvers" != "$new_all_approvers" ] |
| 126 | + then |
| 127 | + # this isn't technically a problem if they all have an approver in common, ie super_approvers is non-empty, suppress warning? |
| 128 | + if [ "$all_approvers" != "" ] |
| 129 | + then |
| 130 | + echo "multiple XEPs modified with different approvers" |
| 131 | + super_approvers="$(comm -12 <(echo "$super_approvers") <(echo "$approvers") | sort -u)" |
| 132 | + exit 1 |
| 133 | + else |
| 134 | + super_approvers="$new_all_approvers" |
| 135 | + fi |
| 136 | + all_approvers="$new_all_approvers" |
| 137 | + fi |
| 138 | + |
| 139 | + # check revision block added and minor version bump |
| 140 | + versions="$(xpath "$xep" '/xep/header/revision/version/text()')" |
| 141 | + latest_num_versions="$(echo "$versions" | wc -l)" |
| 142 | + latest_version="$(echo "$versions" | head -n1)" |
| 143 | + # this git-cat-file usage assumes no entities etc are ever removed from xep.ent etc, this should be true |
| 144 | + # but if it ever isn't, then we'll have to check out the entire repo as of $merge_base to do that |
| 145 | + versions="$(git cat-file -p "$merge_base:./$xep" | xpath - '/xep/header/revision/version/text()')" |
| 146 | + merge_base_num_versions="$(echo "$versions" | wc -l)" |
| 147 | + merge_base_version="$(echo "$versions" | head -n1)" |
| 148 | + if [ $latest_num_versions -gt $merge_base_num_versions ] |
| 149 | + then |
| 150 | + if ! echo "$latest_version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' &>/dev/null |
| 151 | + then |
| 152 | + echo "version is not semver format: '$latest_version'" |
| 153 | + exit 1 |
| 154 | + fi |
| 155 | + if [ "$latest_version" == "$merge_base_version" ] |
| 156 | + then |
| 157 | + add_tag "Needs Version Block" |
| 158 | + # todo: anyone have a fancy way to check semver is higher in $latest_version ? |
| 159 | + # beware we have funky non-semver versions |
| 160 | + # for xep in xep-*.xml; do xpath "$xep" '/xep/header/revision/version/text()'; done | sort -u > xep_versions.txt |
| 161 | + fi |
| 162 | + else |
| 163 | + add_tag "Needs Version Block" |
| 164 | + fi |
| 165 | +done |
| 166 | + |
| 167 | +if [ "$super_approvers" != "" ] |
| 168 | +then |
| 169 | + pr_authors="$(git --no-pager log --format="%aE" "$merge_base".."$pr_commit" | sort -u)" |
| 170 | + pr_authors_super_approvers="$(comm -12 <(echo "$super_approvers") <(echo "$pr_authors") | sort -u)" |
| 171 | + if [ "$pr_authors_super_approvers" != "" ] |
| 172 | + then |
| 173 | + echo "info: entire PR can be approved by one of the commit authors: '$(echo "$pr_authors" | tr '\n' ' ' | xargs)'" |
| 174 | + fi |
| 175 | + echo "info: entire PR can be approved by: '$(echo "$super_approvers" | tr '\n' ' ' | xargs)'" |
| 176 | +fi |
| 177 | + |
| 178 | +if echo "$all_approvers" | grep '^Council$' &>/dev/null |
| 179 | +then |
| 180 | + add_tag "Needs Council" |
| 181 | +fi |
| 182 | + |
| 183 | +if echo "$all_approvers" | grep '^Board$' &>/dev/null |
| 184 | +then |
| 185 | + add_tag "Needs Board" |
| 186 | +fi |
| 187 | + |
| 188 | +if echo "$all_approvers" | grep '^Unknown$' &>/dev/null |
| 189 | +then |
| 190 | + echo "approver is unknown, perhaps old XEP that needs fixed?" |
| 191 | + exit 1 |
| 192 | +fi |
| 193 | + |
| 194 | +if echo "$all_approvers" | grep '@' &>/dev/null |
| 195 | +then |
| 196 | + add_tag "Needs Author" |
| 197 | +fi |
| 198 | + |
| 199 | +echo "manual: if only editorial changes, may not need approval" |
0 commit comments