Skip to content

Instantly share code, notes, and snippets.

@aks
Last active March 15, 2018 15:03
Show Gist options
  • Select an option

  • Save aks/9ac0404e3e523e6c4c4032f54c63a78c to your computer and use it in GitHub Desktop.

Select an option

Save aks/9ac0404e3e523e6c4c4032f54c63a78c to your computer and use it in GitHub Desktop.
Bash script to run rails migrations singly interactively
#!/usr/bin/env bash
# run-migrations-singly
PROG=${0##*/}
DIR=${0%/*}
export PATH=$PATH:$HOME/bin:$HOME/lib
# see github.com/aks/bash-lib
source talk-utils.sh
source run-utils.sh
status_log=migration_statuses.log
usage() {
cat 1>&2 <<EOF
usage: $PROG [-hnv] [STARTDATE [ENDDATE]]
Run rails migrations from STARTDATE until ENDDATE, if given. If a date is
omitted, all available down migrations are used.
Options
-h show this help
-n no run; show commands but don't run them
-v be verbose
EOF
exit
}
migration_statuses() {
talk "Fetching migration statuses in $status_log .."
safe_run "bundle exec rake db:migrate:status"
}
prompt_yes_or_no() {
local ans=
while [[ -z "$ans" ]]; do
read -e -p "Run? [yNq]" ans
[[ -z "$ans" ]] && ans=no
case "$ans" in
yes|y|YES|Y)
return 0 ;;
no|n|NO|n)
return 1 ;;
quit|q|QUIT|q)
talk "Quit!"
exit ;;
*)
ans=
talk "Please answer yes or no" ;;
esac
done
}
start_yet() {
test_limit '>' "$@"
}
not_done_yet() {
test_limit '<' "$@"
}
# test_limit ver lim op
test_limit() {
local op="$1" ver="$2" lim="$3"
if eval "[[ -z \"$lim\" || ( \"$ver\" $op \"$lim\" || \"$ver\" = \"$lim\" ) ]]" ; then
return 0
else
return 1
fi
}
skipped_line() {
if (( skipping )) ; then
if (( verbose )) ; then
talkf "%s (skipped)\n" "$line"
fi
return 0
fi
skipping=1
return 1
}
skipping_msg() {
(( verbose )) || return 0
talk "$line"
talk "$1"
}
# up 20180309183346 Add index to site instruction type
# down 20180312232945 Change alternate formats table all ids to bigints stage 1
run_migrations_up_iteratively() {
local startdate="$1"
local enddate="$2"
local line skipping=0
local updown version message
exec 3<$status_log # open fd 3 on the status log
while read -u 3 line ; do
if [[ "$line" =~ (down|up)\ *([0-9]{14})\ *([^\ ].*)$ ]] ; then
updown="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
message="${BASH_REMATCH[2]}"
case "$updown" in
down)
if start_yet "$version" "$startdate" ; then
if not_done_yet "$version" "$enddate" ; then
talk "$line"
if prompt_yes_or_no ; then
run_migration "$version"
else
talk "Skipped $version"
fi
else # done
skipped_line && continue
skipping_msg "Skipping this and remaining migrations" || break
fi
else # not started yet?
skipped_line && continue
skipping_msg "Skipping this and others until $startdate .." || break
fi
;;
up)
(( verbose )) && talk "$line"
;;
esac
else
(( verbose )) && talk "$line"
fi
done
exec 3<&- # close fd 3
}
run_migration() {
run "bundle exec rake db:migrate:up VERSION=\"$1\""
}
norun= verbose=
while getopts 'hnv' opt ; do
case "$opt" in
h) usage ;;
n) norun=1 ;;
v) verbose=1 ;;
esac
done
shift $(( OPTIND - 1 ))
case $# in
2) startdate="$1" enddate="$2" ;;
1) startdate="$1" enddate= ;;
0) startdate= enddate= ;;
esac
if [[ ! -e $status_log ]] || find $status_log -mtime +1 1 >& /dev/null ; then
migration_statuses >$status_log
fi
run_migrations_up_iteratively "$startdate" "$enddate"
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment