103 lines
2.6 KiB
Bash
Executable File
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[@]}"
|