add "Check cherry-picks" github action

the intention being to catch commits which declare themselves as
cherry-picks, but either:

 - don't refer to a commit in the master or staging branches
 - are significantly altered from their original commit

determining the latter is not an exact science, but the heuristic of
looking for differences in only the added or removed lines seems to
work quite well. still, this should be considered an assistant
for reviewers rather than a hard failure. unfortunately github
workflows don't have a way of raising a gentle warning instead of a
failure.

the formatting of the output also leaves something to be desired due
to the limitations of github actions' "group" commands.
This commit is contained in:
Robert Scott 2022-05-07 12:54:51 +01:00
parent 354e1366a7
commit fbad66daa5
2 changed files with 116 additions and 0 deletions

View file

@ -0,0 +1,24 @@
name: "Check cherry-picks"
on:
pull_request_target:
branches:
- 'release-*'
- 'staging-*'
permissions: {}
jobs:
check:
runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS'
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
filter: blob:none
- name: Check cherry-picks
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
./maintainers/scripts/check-cherry-picks.sh "$BASE_SHA" "$HEAD_SHA"

View file

@ -0,0 +1,92 @@
#!/usr/bin/env bash
# Find alleged cherry-picks
set -e
if [ $# != "2" ] ; then
echo "usage: check-cherry-picks.sh base_rev head_rev"
exit 2
fi
PICKABLE_BRANCHES=${PICKABLE_BRANCHES:-master staging release-??.?? staging-??.??}
problem=0
while read new_commit_sha ; do
if [ "$GITHUB_ACTIONS" = 'true' ] ; then
echo "::group::Commit $new_commit_sha"
else
echo "================================================="
fi
git rev-list --max-count=1 --format=medium "$new_commit_sha"
echo "-------------------------------------------------"
original_commit_sha=$(
git rev-list --max-count=1 --format=format:%B "$new_commit_sha" \
| grep -Ei -m1 "cherry.*[0-9a-f]{40}" \
| grep -Eoi -m1 '[0-9a-f]{40}'
)
if [ "$?" != "0" ] ; then
echo " ? Couldn't locate original commit hash in message"
[ "$GITHUB_ACTIONS" = 'true' ] && echo ::endgroup::
continue
fi
set -f # prevent pathname expansion of patterns
for branch_pattern in $PICKABLE_BRANCHES ; do
set +f # re-enable pathname expansion
while read -r picked_branch ; do
if git merge-base --is-ancestor "$original_commit_sha" "$picked_branch" ; then
echo "$original_commit_sha present in branch $picked_branch"
range_diff_common='git range-diff
--no-notes
--creation-factor=100
'"$original_commit_sha~..$original_commit_sha"'
'"$new_commit_sha~..$new_commit_sha"'
'
if $range_diff_common --no-color | grep -E '^ {4}[+-]{2}' > /dev/null ; then
if [ "$GITHUB_ACTIONS" = 'true' ] ; then
echo ::endgroup::
echo -n "::warning ::"
else
echo -n " ⚠ "
fi
echo "Difference between $new_commit_sha and original $original_commit_sha may warrant inspection:"
$range_diff_common --color
problem=1
else
echo "$original_commit_sha highly similar to $new_commit_sha"
$range_diff_common --color
[ "$GITHUB_ACTIONS" = 'true' ] && echo ::endgroup::
fi
# move on to next commit
continue 3
fi
done <<< "$(
git for-each-ref \
--format="%(refname)" \
"refs/remotes/origin/$branch_pattern"
)"
done
if [ "$GITHUB_ACTIONS" = 'true' ] ; then
echo ::endgroup::
echo -n "::error ::"
else
echo -n " ✘ "
fi
echo "$original_commit_sha not found in any pickable branch"
problem=1
done <<< "$(
git rev-list \
-E -i --grep="cherry.*[0-9a-f]{40}" --reverse \
"$1..$2"
)"
exit $problem