Changeset View
Changeset View
Standalone View
Standalone View
contrib/arcanist/test/test-autopatch.sh
#!/usr/bin/env bash | #!/usr/bin/env bash | ||||
# Copyright (c) 2019 The Bitcoin developers | # Copyright (c) 2019 The Bitcoin developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
export LC_ALL=C.UTF-8 | export LC_ALL=C.UTF-8 | ||||
set -euxo pipefail | set -euo pipefail | ||||
jasonbcox: Reviewer note: I removed `set -x` here because it outputs to stderr by default and isn't… | |||||
TOPLEVEL=$(git rev-parse --show-toplevel) | TOPLEVEL=$(git rev-parse --show-toplevel) | ||||
CURRENT_DIR=$(dirname $(readlink -f "$0")) | CURRENT_DIR=$(dirname $(readlink -f "$0")) | ||||
TEST_PATCH="${CURRENT_DIR}/test-commit.patch" | TEST_PATCH="${CURRENT_DIR}/test-commit.patch" | ||||
: "${REMOTE:=origin}" | : "${REMOTE:=origin}" | ||||
: "${MASTER_BRANCH:=master}" | : "${MASTER_BRANCH:=master}" | ||||
REMOTE_AND_BRANCH="${REMOTE}/${MASTER_BRANCH}" | REMOTE_AND_BRANCH="${REMOTE}/${MASTER_BRANCH}" | ||||
LATEST_MASTER=$(git rev-parse "${REMOTE_AND_BRANCH}") | LATEST_MASTER=$(git rev-parse "${REMOTE_AND_BRANCH}") | ||||
printstderr() { | |||||
>&2 echo "$1" | |||||
} | |||||
test_autopatch() { | test_autopatch() { | ||||
PATCH_FILE="$1" | PATCH_FILE="$1" | ||||
EXPECTED_EXIT_CODE="$2" | EXPECTED_EXIT_CODE="$2" | ||||
PATCH_ARGS="--patch ${PATCH_FILE}" | PATCH_ARGS="--patch ${PATCH_FILE}" | ||||
# Setting the remote to this repo allows us to simulate an upstream without | # Setting the remote to this repo allows us to simulate an upstream without | ||||
# relying on external services for unit tests. | # relying on external services for unit tests. | ||||
export EDITOR="${CURRENT_DIR}/test-commit-message.sh" | export EDITOR="${CURRENT_DIR}/test-commit-message.sh" | ||||
# Note: Do not use `-o ${REMOTE}` here because REMOTE may be on the local filesystem. | # Note: Do not use `-o ${REMOTE}` here because REMOTE may be on the local filesystem. | ||||
EXIT_CODE=0 | EXIT_CODE=0 | ||||
"${CURRENT_DIR}/../autopatch.sh" -o testorigin -b "${MASTER_BRANCH}" --patch-args "${PATCH_ARGS}" || EXIT_CODE=$? | "${CURRENT_DIR}/../autopatch.sh" -o testorigin -b "${MASTER_BRANCH}" --patch-args "${PATCH_ARGS}" 2>&1 || EXIT_CODE=$? | ||||
if [ "${EXIT_CODE}" -ne "${EXPECTED_EXIT_CODE}" ]; then | if [ "${EXIT_CODE}" -ne "${EXPECTED_EXIT_CODE}" ]; then | ||||
echo "Error: autopatch exited with '${EXIT_CODE}' when '${EXPECTED_EXIT_CODE}' was expected." | printstderr "Error: autopatch exited with '${EXIT_CODE}' when '${EXPECTED_EXIT_CODE}' was expected." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Autopatch failed as expected, so sanity checks are not necessary | # Autopatch failed as expected, so sanity checks are not necessary | ||||
if [ "${EXPECTED_EXIT_CODE}" -ne 0 ]; then | if [ "${EXPECTED_EXIT_CODE}" -ne 0 ]; then | ||||
exit 0 | exit 0 | ||||
fi | fi | ||||
# Sanity checks | # Sanity checks | ||||
if [ -n "$(git status --porcelain)" ]; then | if [ -n "$(git status --porcelain)" ]; then | ||||
echo "Error: There should be no uncommitted changes." | printstderr "Error: There should be no uncommitted changes." | ||||
exit 10 | exit 10 | ||||
fi | fi | ||||
if [ "${LATEST_MASTER}" != "$(git rev-parse HEAD~)" ]; then | if [ "${LATEST_MASTER}" != "$(git rev-parse HEAD~)" ]; then | ||||
echo "Error: Failed to patch on latest master." | printstderr "Error: Failed to patch on latest master." | ||||
exit 11 | exit 11 | ||||
fi | fi | ||||
# Note: Remove 'index ...' line from 'git diff' as the SHA1 hash is unlikely | # Note: Remove 'index ...' line from 'git diff' as the SHA1 hash is unlikely | ||||
# to match. | # to match. | ||||
DIFF_HEAD_AGAINST_PATCH="$(git diff HEAD~ | grep -v "^index " | diff - "${PATCH_FILE}" || :)" | DIFF_HEAD_AGAINST_PATCH="$(git diff HEAD~ | grep -v "^index " | diff - "${PATCH_FILE}" || :)" | ||||
if [ -n "${DIFF_HEAD_AGAINST_PATCH}" ]; then | if [ -n "${DIFF_HEAD_AGAINST_PATCH}" ]; then | ||||
echo "Error: Rebased changes do not match the given patch. Difference was:" | printstderr "Error: Rebased changes do not match the given patch. Difference was:" | ||||
echo "${DIFF_HEAD_AGAINST_PATCH}" | printstderr "${DIFF_HEAD_AGAINST_PATCH}" | ||||
exit 12 | exit 12 | ||||
fi | fi | ||||
} | } | ||||
TEST_STATUS="FAILED" | TEST_STATUS="FAILED" | ||||
final_cleanup() { | final_cleanup() { | ||||
# Cleanup the temporary test directory | # Cleanup the temporary test directory | ||||
rm -rf "$1" | rm -rf "$1" | ||||
# Nicely print the final test status | # Print the final test status | ||||
set +x | printstderr "" | ||||
echo | printstderr "${0}:" | ||||
echo "${0}:" | printstderr "${TEST_STATUS}" | ||||
echo "${TEST_STATUS}" | |||||
} | } | ||||
TEMP_DIR=$(mktemp -d) | TEMP_DIR=$(mktemp -d) | ||||
trap 'final_cleanup ${TEMP_DIR}' RETURN EXIT | trap 'final_cleanup ${TEMP_DIR}' RETURN EXIT | ||||
cd "${TEMP_DIR}" | cd "${TEMP_DIR}" | ||||
git init | git init | ||||
git remote add testorigin "${TOPLEVEL}" | git remote add testorigin "${TOPLEVEL}" | ||||
git pull testorigin "${REMOTE_AND_BRANCH}" | git pull testorigin "${REMOTE_AND_BRANCH}" 2>&1 | ||||
test_cleanup() { | test_cleanup() { | ||||
# Cleanup current branch so that arcanist doesn't run out of branch names | # Cleanup current branch so that arcanist doesn't run out of branch names | ||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||||
git checkout "${MASTER_BRANCH}" | git checkout "${MASTER_BRANCH}" 2>&1 | ||||
git reset --hard HEAD | git reset --hard HEAD | ||||
git branch -D "${CURRENT_BRANCH}" || true | git branch -D "${CURRENT_BRANCH}" 2>&1 || true | ||||
} | } | ||||
( | ( | ||||
trap 'test_cleanup' RETURN ERR EXIT | trap 'test_cleanup' RETURN ERR EXIT | ||||
echo "TEST: Simply sanity check that autopatch fast-forwards as expected" | echo "TEST: Simply sanity check that autopatch fast-forwards as expected" | ||||
git reset --hard HEAD~10 | git reset --hard HEAD~10 | ||||
test_autopatch "${TEST_PATCH}" 0 | test_autopatch "${TEST_PATCH}" 0 | ||||
) | ) | ||||
test_file_not_present() { | test_file_not_present() { | ||||
if [ -n "$1" ] && [ -f "$1" ]; then | if [ -n "$1" ] && [ -f "$1" ]; then | ||||
echo "Error: '$1' file was found but not expected!" | printstderr "Error: '$1' file was found but not expected!" | ||||
exit 51 | exit 51 | ||||
fi | fi | ||||
} | } | ||||
( | ( | ||||
trap 'test_cleanup' RETURN ERR EXIT | trap 'test_cleanup' RETURN ERR EXIT | ||||
echo "TEST: Locally committed changes cause the script to bail" | echo "TEST: Locally committed changes cause the script to bail" | ||||
TEST_FILE="test-committed-changes" | TEST_FILE="test-committed-changes" | ||||
Show All 29 Lines |
Reviewer note: I removed set -x here because it outputs to stderr by default and isn't strictly necessary. Under some circumstances, it's possible to change that to stdout by setting export BASH_XTRACEFD=1 but this appears to affect subshells in strange ways.