#!/bin/bash # Ensure commits in beta are in master & commits in stable are in beta + master. set -euo pipefail IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" # We don't care about commits that predate this automation check, so we pass a # `` argument to `git cherry`. BETA_LIMIT="53fd98ca776cb875bc9e5514f56b52eb74f9e7a9" STABLE_LIMIT="a178d0322ce20e33eac124758e837cbd80a6f633" verify_backported_commits_main() { ci_base_branch=$(ciBaseBranch) if [[ "$ci_base_branch" != "beta" && "$ci_base_branch" != "stable" ]]; then echo 'Skipping. This is only run when merging to the beta or stable branches.' exit 0 fi if [[ $ci_base_branch == "beta" ]]; then verify_cherries master "$BETA_LIMIT" \ || exit 1 elif [[ $ci_base_branch == "stable" ]]; then (verify_cherries master "$STABLE_LIMIT" \ & verify_cherries beta "$STABLE_LIMIT") \ || exit 1 fi } # Verify all commits in `HEAD` are backports of a commit in . See # https://git-scm.com/docs/git-cherry for an explanation of the arguments. # # $1 = # $2 = verify_cherries() { # commits that lack a `backport-of` comment. local no_backports=() # commits with an incorrect `backport-of` comment. local bad_backports=() commits=$(git cherry "origin/$1" HEAD "$2") if [[ -z "$commits" ]]; then echo "All commits in \`HEAD\` are present in \`$1\`" return 0 fi commits=$(echo "$commits" | grep '^\+' | cut -c 3-) while read sha; do # Check each commit in .. backport_sha=$(get_backport "$sha") if [[ "$backport_sha" == "nothing" ]]; then echo "✓ \`$sha\` backports nothing" continue fi if [[ -z "$backport_sha" ]]; then no_backports+=("$sha") continue fi if ! is_in_master "$backport_sha"; then bad_backports+=("$sha") continue fi echo "✓ \`$sha\` backports \`$backport_sha\`" done <<< "$commits" failure=0 if [ ${#no_backports[@]} -ne 0 ]; then echo 'Error: Could not find backports for all commits.' echo echo 'All commits in \`HEAD\` are required to have a corresponding upstream commit.' echo 'It looks like the following commits:' echo for commit in "${no_backports[@]}"; do echo " $commit" done echo echo "do not match any commits in \`$1\`. If this was intended, add the text" echo '\`backport-of: \`' echo 'somewhere in the message of each of these commits.' echo failure=1 fi if [ ${#bad_backports[@]} -ne 0 ]; then echo 'Error: Found incorrectly marked commits.' echo echo 'The following commits:' echo for commit in "${bad_backports[@]}"; do echo " $commit" done echo echo 'have commit messages marked \`backport-of: \`, but the SHA is not in' echo '\`master\`.' echo failure=1 fi return $failure } # Get the backport of a commit. It echoes one of: # # 1. A SHA of the backported commit # 2. The string "nothing" # 3. An empty string # # $1 = get_backport() { # This regex is: # # ^.* - throw away any extra starting characters # backport-of: - prefix # \s\? - optional space # \(\) - capture group # [a-f0-9]\+\|nothing - a SHA or the text 'nothing' # .* - throw away any extra ending characters # \1 - replace it with the first match # {s//\1/p;q} - print the first occurrence and quit # git show -s --format=%B "$1" \ | sed -n '/^.*backport-of:\s\?\([a-f0-9]\+\|nothing\).*/{s//\1/p;q}' } # Check if a commit is in master. # # $1 = is_in_master() { git merge-base --is-ancestor "$1" origin/master 2> /dev/null } verify_backported_commits_main