who_need_help/scripts/release-migration-policy.sh

103 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT=${3:-$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)}
previous_commit=${1:-}
target_commit=${2:-HEAD}
policy_path=priv/repo/migration_application_compatibility.tsv
usage() {
echo "Usage: $0 PREVIOUS_COMMIT TARGET_COMMIT [REPOSITORY_ROOT]" >&2
}
if [[ -z "$previous_commit" || -z "$target_commit" ]]; then
usage
exit 2
fi
for commit in "$previous_commit" "$target_commit"; do
git -C "$ROOT" cat-file -e "$commit^{commit}" 2>/dev/null || {
echo "Commit is unavailable in the repository: $commit" >&2
exit 2
}
done
git -C "$ROOT" merge-base --is-ancestor "$previous_commit" "$target_commit" || {
echo "The target commit is not a descendant of the previous commit." >&2
exit 2
}
mapfile -t migration_changes < <(
git -C "$ROOT" diff --name-status "$previous_commit..$target_commit" -- \
'priv/repo/migrations/[0-9]*.exs'
)
if [[ ${#migration_changes[@]} -eq 0 ]]; then
echo "migration_policy=application_safe"
echo "migration_versions=none"
echo "migration_count=0"
exit 0
fi
registry=$(git -C "$ROOT" show "$target_commit:$policy_path" 2>/dev/null) || {
echo "The target commit does not contain $policy_path." >&2
exit 2
}
overall_policy=application_safe
versions=()
for change in "${migration_changes[@]}"; do
status=${change%%$'\t'*}
path=${change#*$'\t'}
if [[ "$status" != A ]]; then
echo "Applied migration files must not be modified, renamed, or deleted: $change" >&2
exit 2
fi
filename=${path##*/}
version=${filename%%_*}
[[ "$version" =~ ^[0-9]{14}$ ]] || {
echo "Migration does not have a 14-digit Ecto version: $path" >&2
exit 2
}
mapfile -t matches < <(
awk -F '\t' -v version="$version" '
$0 !~ /^#/ && $1 == version {print $2 "\t" $3}
' <<<"$registry"
)
if [[ ${#matches[@]} -ne 1 ]]; then
echo "Migration $version must have exactly one entry in $policy_path." >&2
exit 2
fi
policy=${matches[0]%%$'\t'*}
reason=${matches[0]#*$'\t'}
case "$policy" in
application_safe | forward_only) ;;
*)
echo "Migration $version has an invalid application rollback policy: $policy" >&2
exit 2
;;
esac
[[ -n "$reason" && "$reason" != "$policy" ]] || {
echo "Migration $version must document why its policy is correct." >&2
exit 2
}
if [[ "$policy" == forward_only ]]; then
overall_policy=forward_only
fi
versions+=("$version:$policy")
done
printf 'migration_policy=%s\n' "$overall_policy"
printf 'migration_versions=%s\n' "$(IFS=,; echo "${versions[*]}")"
printf 'migration_count=%s\n' "${#versions[@]}"