Merge pull request 'Use apps.json to power upgrade / rollback, add helper commands' (#135) from apps-json into main
continuous-integration/drone/push Build is failing Details

Reviewed-on: #135
This commit is contained in:
decentral1se 2021-04-05 15:50:57 +02:00
commit 48a7bb8c2d
3 changed files with 474 additions and 238 deletions

626
abra
View File

@ -5,7 +5,7 @@ ABRA_DIR="${ABRA_DIR:-$HOME/.abra}"
ABRA_VERSION="0.6.0" ABRA_VERSION="0.6.0"
ABRA_BACKUP_DIR="${ABRA_BACKUP_DIR:-$ABRA_DIR/backups}" ABRA_BACKUP_DIR="${ABRA_BACKUP_DIR:-$ABRA_DIR/backups}"
ABRA_VENDOR_DIR="$ABRA_DIR/vendor" ABRA_VENDOR_DIR="$ABRA_DIR/vendor"
YQ="$ABRA_VENDOR_DIR/yq" ABRA_APPS_JSON="${ABRA_DIR}/apps.json"
####################################### #######################################
# Global help # Global help
@ -18,7 +18,7 @@ Usage:
abra [options] app (list|ls) [--status] [--server=<server>] [--type=<type>] abra [options] app (list|ls) [--status] [--server=<server>] [--type=<type>]
abra [options] app new [--server=<server>] [--domain=<domain>] [--app-name=<app_name>] [--pass] [--secrets] <type> abra [options] app new [--server=<server>] [--domain=<domain>] [--app-name=<app_name>] [--pass] [--secrets] <type>
abra [options] app <app> backup (<service>|--all) abra [options] app <app> backup (<service>|--all)
abra [options] app <app> deploy [--update] [--force] [--skip-version-check] abra [options] app <app> deploy [--update] [--force] [--skip-version-check] [<version>]
abra [options] app <app> check abra [options] app <app> check
abra [options] app <app> version abra [options] app <app> version
abra [options] app <app> config abra [options] app <app> config
@ -29,12 +29,15 @@ Usage:
abra [options] app <app> (rm|delete) [--volumes] [--secrets] abra [options] app <app> (rm|delete) [--volumes] [--secrets]
abra [options] app <app> restore <service> [<backup file>] abra [options] app <app> restore <service> [<backup file>]
abra [options] app <app> run [--no-tty] [--user=<user>] <service> <args>... abra [options] app <app> run [--no-tty] [--user=<user>] <service> <args>...
abra [options] app <app> rollback <service> abra [options] app <app> rollback [<version>]
abra [options] app <app> secret generate (<secret> <version>|--all) [<cmd>] [--pass] abra [options] app <app> secret generate (<secret> <version>|--all) [<cmd>] [--pass]
abra [options] app <app> secret insert <secret> <version> <data> [--pass] abra [options] app <app> secret insert <secret> <version> <data> [--pass]
abra [options] app <app> secret (rm|delete) (<secret>|--all) [--pass] abra [options] app <app> secret (rm|delete) (<secret>|--all) [--pass]
abra [options] app <app> undeploy abra [options] app <app> undeploy
abra [options] app <app> <command> [<args>...] abra [options] app <app> <command> [<args>...]
abra [options] recipe ls
abra [options] recipe <recipe> release [--force]
abra [options] recipe <recipe> versions
abra [options] server add <host> [<user>] [<port>] abra [options] server add <host> [<user>] [<port>]
abra [options] server new <provider> abra [options] server new <provider>
abra [options] server (list|ls) abra [options] server (list|ls)
@ -160,15 +163,15 @@ eval "var_$1+=($value)"; else eval "var_$1=$value"; fi; return 0; fi; done
return 1; }; stdout() { printf -- "cat <<'EOM'\n%s\nEOM\n" "$1"; }; stderr() { return 1; }; stdout() { printf -- "cat <<'EOM'\n%s\nEOM\n" "$1"; }; stderr() {
printf -- "cat <<'EOM' >&2\n%s\nEOM\n" "$1"; }; error() { printf -- "cat <<'EOM' >&2\n%s\nEOM\n" "$1"; }; error() {
[[ -n $1 ]] && stderr "$1"; stderr "$usage"; _return 1; }; _return() { [[ -n $1 ]] && stderr "$1"; stderr "$usage"; _return 1; }; _return() {
printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:2162} printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:2296}
usage=${DOC:40:1553}; digest=b3855 usage=${DOC:40:1687}; digest=4e473
shorts=(-n -b -s -v -h -C -U -d -e '' '' '' '' '' '' '' '' '' '' '' '' '' '' '') shorts=(-e -d -b -n -v -s -C -U -h '' '' '' '' '' '' '' '' '' '' '' '' '' '' '')
longs=(--no-prompt --branch --stack --verbose --help --skip-check --skip-update --debug --env --status --server --type --domain --app-name --pass --secrets --all --update --force --skip-version-check --volumes --no-tty --user --dev) longs=(--env --debug --branch --no-prompt --verbose --stack --skip-check --skip-update --help --status --server --type --domain --app-name --pass --secrets --all --update --force --skip-version-check --volumes --no-tty --user --dev)
argcounts=(0 1 1 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0); node_0(){ argcounts=(1 0 1 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0); node_0(){
switch __no_prompt 0; }; node_1(){ value __branch 1; }; node_2(){ value __env 0; }; node_1(){ switch __debug 1; }; node_2(){ value __branch 2; }
value __stack 2; }; node_3(){ switch __verbose 3; }; node_4(){ switch __help 4 node_3(){ switch __no_prompt 3; }; node_4(){ switch __verbose 4; }; node_5(){
}; node_5(){ switch __skip_check 5; }; node_6(){ switch __skip_update 6; } value __stack 5; }; node_6(){ switch __skip_check 6; }; node_7(){
node_7(){ switch __debug 7; }; node_8(){ value __env 8; }; node_9(){ switch __skip_update 7; }; node_8(){ switch __help 8; }; node_9(){
switch __status 9; }; node_10(){ value __server 10; }; node_11(){ switch __status 9; }; node_10(){ value __server 10; }; node_11(){
value __type 11; }; node_12(){ value __domain 12; }; node_13(){ value __type 11; }; node_12(){ value __domain 12; }; node_13(){
value __app_name 13; }; node_14(){ switch __pass 14; }; node_15(){ value __app_name 13; }; node_14(){ switch __pass 14; }; node_15(){
@ -177,97 +180,103 @@ switch __update 17; }; node_18(){ switch __force 18; }; node_19(){
switch __skip_version_check 19; }; node_20(){ switch __volumes 20; }; node_21(){ switch __skip_version_check 19; }; node_20(){ switch __volumes 20; }; node_21(){
switch __no_tty 21; }; node_22(){ value __user 22; }; node_23(){ switch __dev 23 switch __no_tty 21; }; node_22(){ value __user 22; }; node_23(){ switch __dev 23
}; node_24(){ value _type_ a; }; node_25(){ value _app_ a; }; node_26(){ }; node_24(){ value _type_ a; }; node_25(){ value _app_ a; }; node_26(){
value _service_ a; }; node_27(){ value _src_ a; }; node_28(){ value _dst_ a; } value _service_ a; }; node_27(){ value _version_ a; }; node_28(){ value _src_ a
node_29(){ value _backup_file_ a; }; node_30(){ value _args_ a true; } }; node_29(){ value _dst_ a; }; node_30(){ value _backup_file_ a; }; node_31(){
node_31(){ value _secret_ a; }; node_32(){ value _version_ a; }; node_33(){ value _args_ a true; }; node_32(){ value _secret_ a; }; node_33(){ value _cmd_ a
value _cmd_ a; }; node_34(){ value _data_ a; }; node_35(){ value _command_ a; } }; node_34(){ value _data_ a; }; node_35(){ value _command_ a; }; node_36(){
node_36(){ value _host_ a; }; node_37(){ value _user_ a; }; node_38(){ value _recipe_ a; }; node_37(){ value _host_ a; }; node_38(){ value _user_ a; }
value _port_ a; }; node_39(){ value _provider_ a; }; node_40(){ node_39(){ value _port_ a; }; node_40(){ value _provider_ a; }; node_41(){
value _subcommands_ a true; }; node_41(){ _command app; }; node_42(){ value _subcommands_ a true; }; node_42(){ _command app; }; node_43(){
_command list; }; node_43(){ _command ls; }; node_44(){ _command new; } _command list; }; node_44(){ _command ls; }; node_45(){ _command new; }
node_45(){ _command backup; }; node_46(){ _command deploy; }; node_47(){ node_46(){ _command backup; }; node_47(){ _command deploy; }; node_48(){
_command check; }; node_48(){ _command version; }; node_49(){ _command config; } _command check; }; node_49(){ _command version; }; node_50(){ _command config; }
node_50(){ _command cp; }; node_51(){ _command logs; }; node_52(){ _command ps node_51(){ _command cp; }; node_52(){ _command logs; }; node_53(){ _command ps
}; node_53(){ _command restore; }; node_54(){ _command rm; }; node_55(){ }; node_54(){ _command restore; }; node_55(){ _command rm; }; node_56(){
_command delete; }; node_56(){ _command run; }; node_57(){ _command rollback; } _command delete; }; node_57(){ _command run; }; node_58(){ _command rollback; }
node_58(){ _command secret; }; node_59(){ _command generate; }; node_60(){ node_59(){ _command secret; }; node_60(){ _command generate; }; node_61(){
_command insert; }; node_61(){ _command undeploy; }; node_62(){ _command server _command insert; }; node_62(){ _command undeploy; }; node_63(){ _command recipe
}; node_63(){ _command add; }; node_64(){ _command init; }; node_65(){ }; node_64(){ _command release; }; node_65(){ _command versions; }; node_66(){
_command apps; }; node_66(){ _command upgrade; }; node_67(){ _command doctor; } _command server; }; node_67(){ _command add; }; node_68(){ _command init; }
node_68(){ _command help; }; node_69(){ optional 0 1 2 3 4 5 6 7 8; } node_69(){ _command apps; }; node_70(){ _command upgrade; }; node_71(){
node_70(){ optional 69; }; node_71(){ either 42 43; }; node_72(){ required 71; } _command doctor; }; node_72(){ _command help; }; node_73(){
node_73(){ optional 9; }; node_74(){ optional 10; }; node_75(){ optional 11; } optional 0 1 2 3 4 5 6 7 8; }; node_74(){ optional 73; }; node_75(){
node_76(){ required 70 41 72 73 74 75; }; node_77(){ optional 12; }; node_78(){ either 43 44; }; node_76(){ required 75; }; node_77(){ optional 9; }; node_78(){
optional 13; }; node_79(){ optional 14; }; node_80(){ optional 15; }; node_81(){ optional 10; }; node_79(){ optional 11; }; node_80(){ required 74 42 76 77 78 79
required 70 41 44 74 77 78 79 80 24; }; node_82(){ either 26 16; }; node_83(){ }; node_81(){ optional 12; }; node_82(){ optional 13; }; node_83(){ optional 14
required 82; }; node_84(){ required 70 41 25 45 83; }; node_85(){ optional 17; } }; node_84(){ optional 15; }; node_85(){ required 74 42 45 78 81 82 83 84 24; }
node_86(){ optional 18; }; node_87(){ optional 19; }; node_88(){ node_86(){ either 26 16; }; node_87(){ required 86; }; node_88(){
required 70 41 25 46 85 86 87; }; node_89(){ required 70 41 25 47; }; node_90(){ required 74 42 25 46 87; }; node_89(){ optional 17; }; node_90(){ optional 18; }
required 70 41 25 48; }; node_91(){ required 70 41 25 49; }; node_92(){ node_91(){ optional 19; }; node_92(){ optional 27; }; node_93(){
required 70 41 25 50 27 28; }; node_93(){ optional 26; }; node_94(){ required 74 42 25 47 89 90 91 92; }; node_94(){ required 74 42 25 48; }
required 70 41 25 51 93; }; node_95(){ required 70 41 25 52; }; node_96(){ node_95(){ required 74 42 25 49; }; node_96(){ required 74 42 25 50; }
required 70 41 25 53 83; }; node_97(){ either 54 55; }; node_98(){ required 97 node_97(){ required 74 42 25 51 28 29; }; node_98(){ optional 26; }; node_99(){
}; node_99(){ optional 20; }; node_100(){ required 70 41 25 98 99 80; } required 74 42 25 52 98; }; node_100(){ required 74 42 25 53; }; node_101(){
node_101(){ optional 29; }; node_102(){ required 70 41 25 53 26 101; } required 74 42 25 54 87; }; node_102(){ either 55 56; }; node_103(){
node_103(){ optional 21; }; node_104(){ optional 22; }; node_105(){ oneormore 30 required 102; }; node_104(){ optional 20; }; node_105(){
}; node_106(){ required 70 41 25 56 103 104 26 105; }; node_107(){ required 74 42 25 103 104 84; }; node_106(){ optional 30; }; node_107(){
required 70 41 25 57 26; }; node_108(){ required 31 32; }; node_109(){ required 74 42 25 54 26 106; }; node_108(){ optional 21; }; node_109(){
either 108 16; }; node_110(){ required 109; }; node_111(){ optional 33; } optional 22; }; node_110(){ oneormore 31; }; node_111(){
node_112(){ required 70 41 25 58 59 110 111 79; }; node_113(){ required 74 42 25 57 108 109 26 110; }; node_112(){ required 74 42 25 58 92; }
required 70 41 25 58 60 31 32 34 79; }; node_114(){ either 31 16; }; node_115(){ node_113(){ required 32 27; }; node_114(){ either 113 16; }; node_115(){
required 114; }; node_116(){ required 70 41 25 58 98 115 79; }; node_117(){ required 114; }; node_116(){ optional 33; }; node_117(){
required 70 41 25 61; }; node_118(){ optional 105; }; node_119(){ required 74 42 25 59 60 115 116 83; }; node_118(){
required 70 41 25 35 118; }; node_120(){ optional 37; }; node_121(){ optional 38 required 74 42 25 59 61 32 27 34 83; }; node_119(){ either 32 16; }; node_120(){
}; node_122(){ required 70 62 63 36 120 121; }; node_123(){ required 70 62 44 39 required 119; }; node_121(){ required 74 42 25 59 103 120 83; }; node_122(){
}; node_124(){ required 70 62 72; }; node_125(){ required 70 62 36 54; } required 74 42 25 62; }; node_123(){ optional 110; }; node_124(){
node_126(){ required 70 62 36 64; }; node_127(){ required 70 62 36 65 73; } required 74 42 25 35 123; }; node_125(){ required 74 63 44; }; node_126(){
node_128(){ optional 23; }; node_129(){ required 70 66 128; }; node_130(){ required 74 63 36 64 90; }; node_127(){ required 74 63 36 65; }; node_128(){
required 70 48; }; node_131(){ required 70 67; }; node_132(){ oneormore 40; } optional 38; }; node_129(){ optional 39; }; node_130(){
node_133(){ optional 132; }; node_134(){ required 70 68 133; }; node_135(){ required 74 66 67 37 128 129; }; node_131(){ required 74 66 45 40; }
required 70; }; node_136(){ node_132(){ required 74 66 76; }; node_133(){ required 74 66 37 55; }
either 76 81 84 88 89 90 91 92 94 95 96 100 102 106 107 112 113 116 117 119 122 123 124 125 126 127 129 130 131 134 135 node_134(){ required 74 66 37 68; }; node_135(){ required 74 66 37 69 77; }
}; node_137(){ required 136; }; cat <<<' docopt_exit() { node_136(){ optional 23; }; node_137(){ required 74 70 136; }; node_138(){
[[ -n $1 ]] && printf "%s\n" "$1" >&2; printf "%s\n" "${DOC:40:1553}" >&2 required 74 49; }; node_139(){ required 74 71; }; node_140(){ oneormore 41; }
exit 1; }'; unset var___no_prompt var___branch var___stack var___verbose \ node_141(){ optional 140; }; node_142(){ required 74 72 141; }; node_143(){
var___help var___skip_check var___skip_update var___debug var___env \ required 74; }; node_144(){
either 80 85 88 93 94 95 96 97 99 100 101 105 107 111 112 117 118 121 122 124 125 126 127 130 131 132 133 134 135 137 138 139 142 143
}; node_145(){ required 144; }; cat <<<' docopt_exit() {
[[ -n $1 ]] && printf "%s\n" "$1" >&2; printf "%s\n" "${DOC:40:1687}" >&2
exit 1; }'; unset var___env var___debug var___branch var___no_prompt \
var___verbose var___stack var___skip_check var___skip_update var___help \
var___status var___server var___type var___domain var___app_name var___pass \ var___status var___server var___type var___domain var___app_name var___pass \
var___secrets var___all var___update var___force var___skip_version_check \ var___secrets var___all var___update var___force var___skip_version_check \
var___volumes var___no_tty var___user var___dev var__type_ var__app_ \ var___volumes var___no_tty var___user var___dev var__type_ var__app_ \
var__service_ var__src_ var__dst_ var__backup_file_ var__args_ var__secret_ \ var__service_ var__version_ var__src_ var__dst_ var__backup_file_ var__args_ \
var__version_ var__cmd_ var__data_ var__command_ var__host_ var__user_ \ var__secret_ var__cmd_ var__data_ var__command_ var__recipe_ var__host_ \
var__port_ var__provider_ var__subcommands_ var_app var_list var_ls var_new \ var__user_ var__port_ var__provider_ var__subcommands_ var_app var_list var_ls \
var_backup var_deploy var_check var_version var_config var_cp var_logs var_ps \ var_new var_backup var_deploy var_check var_version var_config var_cp var_logs \
var_restore var_rm var_delete var_run var_rollback var_secret var_generate \ var_ps var_restore var_rm var_delete var_run var_rollback var_secret \
var_insert var_undeploy var_server var_add var_init var_apps var_upgrade \ var_generate var_insert var_undeploy var_recipe var_release var_versions \
var_doctor var_help; parse 137 "$@"; local prefix=${DOCOPT_PREFIX:-''} var_server var_add var_init var_apps var_upgrade var_doctor var_help
unset "${prefix}__no_prompt" "${prefix}__branch" "${prefix}__stack" \ parse 145 "$@"; local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__env" \
"${prefix}__verbose" "${prefix}__help" "${prefix}__skip_check" \ "${prefix}__debug" "${prefix}__branch" "${prefix}__no_prompt" \
"${prefix}__skip_update" "${prefix}__debug" "${prefix}__env" \ "${prefix}__verbose" "${prefix}__stack" "${prefix}__skip_check" \
"${prefix}__status" "${prefix}__server" "${prefix}__type" "${prefix}__domain" \ "${prefix}__skip_update" "${prefix}__help" "${prefix}__status" \
"${prefix}__server" "${prefix}__type" "${prefix}__domain" \
"${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \ "${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \
"${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \ "${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \
"${prefix}__volumes" "${prefix}__no_tty" "${prefix}__user" "${prefix}__dev" \ "${prefix}__volumes" "${prefix}__no_tty" "${prefix}__user" "${prefix}__dev" \
"${prefix}_type_" "${prefix}_app_" "${prefix}_service_" "${prefix}_src_" \ "${prefix}_type_" "${prefix}_app_" "${prefix}_service_" "${prefix}_version_" \
"${prefix}_dst_" "${prefix}_backup_file_" "${prefix}_args_" \ "${prefix}_src_" "${prefix}_dst_" "${prefix}_backup_file_" "${prefix}_args_" \
"${prefix}_secret_" "${prefix}_version_" "${prefix}_cmd_" "${prefix}_data_" \ "${prefix}_secret_" "${prefix}_cmd_" "${prefix}_data_" "${prefix}_command_" \
"${prefix}_command_" "${prefix}_host_" "${prefix}_user_" "${prefix}_port_" \ "${prefix}_recipe_" "${prefix}_host_" "${prefix}_user_" "${prefix}_port_" \
"${prefix}_provider_" "${prefix}_subcommands_" "${prefix}app" "${prefix}list" \ "${prefix}_provider_" "${prefix}_subcommands_" "${prefix}app" "${prefix}list" \
"${prefix}ls" "${prefix}new" "${prefix}backup" "${prefix}deploy" \ "${prefix}ls" "${prefix}new" "${prefix}backup" "${prefix}deploy" \
"${prefix}check" "${prefix}version" "${prefix}config" "${prefix}cp" \ "${prefix}check" "${prefix}version" "${prefix}config" "${prefix}cp" \
"${prefix}logs" "${prefix}ps" "${prefix}restore" "${prefix}rm" \ "${prefix}logs" "${prefix}ps" "${prefix}restore" "${prefix}rm" \
"${prefix}delete" "${prefix}run" "${prefix}rollback" "${prefix}secret" \ "${prefix}delete" "${prefix}run" "${prefix}rollback" "${prefix}secret" \
"${prefix}generate" "${prefix}insert" "${prefix}undeploy" "${prefix}server" \ "${prefix}generate" "${prefix}insert" "${prefix}undeploy" "${prefix}recipe" \
"${prefix}add" "${prefix}init" "${prefix}apps" "${prefix}upgrade" \ "${prefix}release" "${prefix}versions" "${prefix}server" "${prefix}add" \
"${prefix}doctor" "${prefix}help" "${prefix}init" "${prefix}apps" "${prefix}upgrade" "${prefix}doctor" \
eval "${prefix}"'__no_prompt=${var___no_prompt:-false}' "${prefix}help"; eval "${prefix}"'__env=${var___env:-}'
eval "${prefix}"'__debug=${var___debug:-false}'
eval "${prefix}"'__branch=${var___branch:-}' eval "${prefix}"'__branch=${var___branch:-}'
eval "${prefix}"'__stack=${var___stack:-}' eval "${prefix}"'__no_prompt=${var___no_prompt:-false}'
eval "${prefix}"'__verbose=${var___verbose:-false}' eval "${prefix}"'__verbose=${var___verbose:-false}'
eval "${prefix}"'__help=${var___help:-false}' eval "${prefix}"'__stack=${var___stack:-}'
eval "${prefix}"'__skip_check=${var___skip_check:-false}' eval "${prefix}"'__skip_check=${var___skip_check:-false}'
eval "${prefix}"'__skip_update=${var___skip_update:-false}' eval "${prefix}"'__skip_update=${var___skip_update:-false}'
eval "${prefix}"'__debug=${var___debug:-false}' eval "${prefix}"'__help=${var___help:-false}'
eval "${prefix}"'__env=${var___env:-}'
eval "${prefix}"'__status=${var___status:-false}' eval "${prefix}"'__status=${var___status:-false}'
eval "${prefix}"'__server=${var___server:-}' eval "${prefix}"'__server=${var___server:-}'
eval "${prefix}"'__type=${var___type:-}' eval "${prefix}"'__type=${var___type:-}'
@ -285,14 +294,15 @@ eval "${prefix}"'__user=${var___user:-}'
eval "${prefix}"'__dev=${var___dev:-false}' eval "${prefix}"'__dev=${var___dev:-false}'
eval "${prefix}"'_type_=${var__type_:-}'; eval "${prefix}"'_app_=${var__app_:-}' eval "${prefix}"'_type_=${var__type_:-}'; eval "${prefix}"'_app_=${var__app_:-}'
eval "${prefix}"'_service_=${var__service_:-}' eval "${prefix}"'_service_=${var__service_:-}'
eval "${prefix}"'_version_=${var__version_:-}'
eval "${prefix}"'_src_=${var__src_:-}'; eval "${prefix}"'_dst_=${var__dst_:-}' eval "${prefix}"'_src_=${var__src_:-}'; eval "${prefix}"'_dst_=${var__dst_:-}'
eval "${prefix}"'_backup_file_=${var__backup_file_:-}' eval "${prefix}"'_backup_file_=${var__backup_file_:-}'
if declare -p var__args_ >/dev/null 2>&1; then if declare -p var__args_ >/dev/null 2>&1; then
eval "${prefix}"'_args_=("${var__args_[@]}")'; else eval "${prefix}"'_args_=()' eval "${prefix}"'_args_=("${var__args_[@]}")'; else eval "${prefix}"'_args_=()'
fi; eval "${prefix}"'_secret_=${var__secret_:-}' fi; eval "${prefix}"'_secret_=${var__secret_:-}'
eval "${prefix}"'_version_=${var__version_:-}'
eval "${prefix}"'_cmd_=${var__cmd_:-}'; eval "${prefix}"'_data_=${var__data_:-}' eval "${prefix}"'_cmd_=${var__cmd_:-}'; eval "${prefix}"'_data_=${var__data_:-}'
eval "${prefix}"'_command_=${var__command_:-}' eval "${prefix}"'_command_=${var__command_:-}'
eval "${prefix}"'_recipe_=${var__recipe_:-}'
eval "${prefix}"'_host_=${var__host_:-}' eval "${prefix}"'_host_=${var__host_:-}'
eval "${prefix}"'_user_=${var__user_:-}' eval "${prefix}"'_user_=${var__user_:-}'
eval "${prefix}"'_port_=${var__port_:-}' eval "${prefix}"'_port_=${var__port_:-}'
@ -318,6 +328,9 @@ eval "${prefix}"'secret=${var_secret:-false}'
eval "${prefix}"'generate=${var_generate:-false}' eval "${prefix}"'generate=${var_generate:-false}'
eval "${prefix}"'insert=${var_insert:-false}' eval "${prefix}"'insert=${var_insert:-false}'
eval "${prefix}"'undeploy=${var_undeploy:-false}' eval "${prefix}"'undeploy=${var_undeploy:-false}'
eval "${prefix}"'recipe=${var_recipe:-false}'
eval "${prefix}"'release=${var_release:-false}'
eval "${prefix}"'versions=${var_versions:-false}'
eval "${prefix}"'server=${var_server:-false}' eval "${prefix}"'server=${var_server:-false}'
eval "${prefix}"'add=${var_add:-false}' eval "${prefix}"'add=${var_add:-false}'
eval "${prefix}"'init=${var_init:-false}' eval "${prefix}"'init=${var_init:-false}'
@ -326,25 +339,26 @@ eval "${prefix}"'upgrade=${var_upgrade:-false}'
eval "${prefix}"'doctor=${var_doctor:-false}' eval "${prefix}"'doctor=${var_doctor:-false}'
eval "${prefix}"'help=${var_help:-false}'; local docopt_i=1 eval "${prefix}"'help=${var_help:-false}'; local docopt_i=1
[[ $BASH_VERSION =~ ^4.3 ]] && docopt_i=2; for ((;docopt_i>0;docopt_i--)); do [[ $BASH_VERSION =~ ^4.3 ]] && docopt_i=2; for ((;docopt_i>0;docopt_i--)); do
declare -p "${prefix}__no_prompt" "${prefix}__branch" "${prefix}__stack" \ declare -p "${prefix}__env" "${prefix}__debug" "${prefix}__branch" \
"${prefix}__verbose" "${prefix}__help" "${prefix}__skip_check" \ "${prefix}__no_prompt" "${prefix}__verbose" "${prefix}__stack" \
"${prefix}__skip_update" "${prefix}__debug" "${prefix}__env" \ "${prefix}__skip_check" "${prefix}__skip_update" "${prefix}__help" \
"${prefix}__status" "${prefix}__server" "${prefix}__type" "${prefix}__domain" \ "${prefix}__status" "${prefix}__server" "${prefix}__type" "${prefix}__domain" \
"${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \ "${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \
"${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \ "${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \
"${prefix}__volumes" "${prefix}__no_tty" "${prefix}__user" "${prefix}__dev" \ "${prefix}__volumes" "${prefix}__no_tty" "${prefix}__user" "${prefix}__dev" \
"${prefix}_type_" "${prefix}_app_" "${prefix}_service_" "${prefix}_src_" \ "${prefix}_type_" "${prefix}_app_" "${prefix}_service_" "${prefix}_version_" \
"${prefix}_dst_" "${prefix}_backup_file_" "${prefix}_args_" \ "${prefix}_src_" "${prefix}_dst_" "${prefix}_backup_file_" "${prefix}_args_" \
"${prefix}_secret_" "${prefix}_version_" "${prefix}_cmd_" "${prefix}_data_" \ "${prefix}_secret_" "${prefix}_cmd_" "${prefix}_data_" "${prefix}_command_" \
"${prefix}_command_" "${prefix}_host_" "${prefix}_user_" "${prefix}_port_" \ "${prefix}_recipe_" "${prefix}_host_" "${prefix}_user_" "${prefix}_port_" \
"${prefix}_provider_" "${prefix}_subcommands_" "${prefix}app" "${prefix}list" \ "${prefix}_provider_" "${prefix}_subcommands_" "${prefix}app" "${prefix}list" \
"${prefix}ls" "${prefix}new" "${prefix}backup" "${prefix}deploy" \ "${prefix}ls" "${prefix}new" "${prefix}backup" "${prefix}deploy" \
"${prefix}check" "${prefix}version" "${prefix}config" "${prefix}cp" \ "${prefix}check" "${prefix}version" "${prefix}config" "${prefix}cp" \
"${prefix}logs" "${prefix}ps" "${prefix}restore" "${prefix}rm" \ "${prefix}logs" "${prefix}ps" "${prefix}restore" "${prefix}rm" \
"${prefix}delete" "${prefix}run" "${prefix}rollback" "${prefix}secret" \ "${prefix}delete" "${prefix}run" "${prefix}rollback" "${prefix}secret" \
"${prefix}generate" "${prefix}insert" "${prefix}undeploy" "${prefix}server" \ "${prefix}generate" "${prefix}insert" "${prefix}undeploy" "${prefix}recipe" \
"${prefix}add" "${prefix}init" "${prefix}apps" "${prefix}upgrade" \ "${prefix}release" "${prefix}versions" "${prefix}server" "${prefix}add" \
"${prefix}doctor" "${prefix}help"; done; } "${prefix}init" "${prefix}apps" "${prefix}upgrade" "${prefix}doctor" \
"${prefix}help"; done; }
# docopt parser above, complete command for generating this parser is `docopt.sh abra` # docopt parser above, complete command for generating this parser is `docopt.sh abra`
PROGRAM_NAME=$(basename "$0") PROGRAM_NAME=$(basename "$0")
@ -434,7 +448,59 @@ require_consent_for_update() {
fi fi
} }
require_plugin (){ require_docker_version() {
get_servers
MIN_DOCKER_VERSION=19
SERVERS+=("default")
for SERVER in "${SERVERS[@]}"; do
SERVER="${SERVER##*/}" # basename
host=$(docker context inspect "$SERVER" -f "{{.Endpoints.docker.Host}}" 2>/dev/null)
if [[ -n "$host" ]]; then
major_version=$(DOCKER_CONTEXT="$SERVER" docker version --format "{{.Server.Version}}" | cut -d'.' -f1 2>/dev/null)
if [[ "$major_version" -lt "$MIN_DOCKER_VERSION" ]]; then
error "This tool requires Docker v${MIN_DOCKER_VERSION} or greater. Please upgrade your Docker installation on $SERVER"
exit 1
else
debug "Docker version on $SERVER is sufficient (v${major_version})"
fi
fi
done
}
###### Download and update data
require_apps_json() {
# Ensure we have the latest copy of apps.json
if [ "$abra___skip_update" = "true" ]; then
return
fi
apps_url="https://abra-apps.cloud.autonomic.zone"
if [ -f "$ABRA_APPS_JSON" ]; then
modified=$(curl --silent --head $apps_url | \
awk '/^Last-Modified/{print $0}' | \
sed 's/^Last-Modified: //')
remote_ctime=$(date --date="$modified" +%s)
local_ctime=$(stat -c %Z "$ABRA_APPS_JSON")
if [ "$local_ctime" -lt "$remote_ctime" ]; then
info "Downloading new apps.json"
wget -qO "$ABRA_APPS_JSON" $apps_url
else
debug "No apps.json update needed"
fi
else
info "Downloading apps.json"
wget -qO "$ABRA_APPS_JSON" $apps_url
fi
}
require_plugin() {
PLUGIN="$1" PLUGIN="$1"
BRANCH="${abra___branch:-master}" BRANCH="${abra___branch:-master}"
@ -475,16 +541,19 @@ require_app (){
error "Could not retrieve app type '$APP', this app type doesn't exist?" error "Could not retrieve app type '$APP', this app type doesn't exist?"
fi fi
cd "$APP_DIR" && checkout_main_or_master
if [[ $(cd "$ABRA_DIR/apps/$APP" && git branch --list | wc -l) == "0" ]]; then if [[ $(cd "$ABRA_DIR/apps/$APP" && git branch --list | wc -l) == "0" ]]; then
debug "Failed to clone default branch, guessing alternative is 'main'" debug "Failed to clone default branch, guessing alternative is 'main'"
(cd "$ABRA_DIR/apps/$APP" && git checkout main > /dev/null 2>&1) (cd "$ABRA_DIR/apps/$APP" && git checkout main)
fi fi
success "Fetched app configuration via Git" success "Fetched app configuration via Git"
} }
require_app_latest() { require_app_version() {
APP="$1" APP="$1"
VERSION="$2"
APP_DIR="$ABRA_DIR/apps/$APP" APP_DIR="$ABRA_DIR/apps/$APP"
debug "Checking for type '$APP'" debug "Checking for type '$APP'"
@ -494,59 +563,58 @@ require_app_latest() {
fi fi
debug "Using $APP_DIR" debug "Using $APP_DIR"
cd "$APP_DIR" || error "Can't find app dir '$APP_DIR'"
if [ "$abra___skip_update" = "false" ]; then if ! git tag -l | grep -q "$VERSION"; then
debug "Pulling latest '$APP' definition via git" git fetch -q --all
(cd "$APP_DIR" && git pull > /dev/null 2>&1)
fi fi
git checkout -q "$VERSION" || error "Can't find version $VERSION"
} }
require_yq() { vendor_binary() {
require_vendor_dir require_vendor_dir
require_binary wget require_binary wget
YQ_VERSION="4.6.1" local REPO="$1"
YQ_BINARY="yq_linux_amd64" local VERSION="$2"
YQ_RELEASE_URL="https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/${YQ_BINARY}" local FILE="$3"
local BINARY="${REPO##*/}"
local RELEASE_URL="$REPO/releases/download/${VERSION}/${FILE}"
if [ -f "$YQ" ]; then # Make the path to the binary available as a similarly-named variable, e.g.
debug "yq is already vendored" # yq -> $YQ
export "${BINARY^^}=$ABRA_VENDOR_DIR/$BINARY"
if [ -f "$ABRA_DIR/vendor/$BINARY" ]; then
debug "$BINARY is already vendored"
return return
fi fi
case $(uname -m) in case $(uname -m) in
x86_64) x86_64)
warning "Attempting to download the yq binary into $ABRA_VENDOR_DIR" warning "Attempting to download the $BINARY binary from $RELEASE_URL into $ABRA_VENDOR_DIR"
wget -q "$YQ_RELEASE_URL" && chmod +x "$YQ_BINARY" && mv "$YQ_BINARY" "$YQ"
success "yq is now vendored ☮"
;; ;;
*) *)
error "Unable to automatically vendor yq, you'll have to manually manage this\n error "Unable to automatically vendor $BINARY, you'll have to manually manage this.\n
Please see https://mikefarah.gitbook.io/yq/#install and place the yq binary in the $YQ path" Please see $REPO and place the $BINARY binary in $ABRA_VENDOR_DIR."
;; ;;
esac esac
wget -qO "$ABRA_VENDOR_DIR/$BINARY" "$RELEASE_URL" && chmod +x "$ABRA_VENDOR_DIR/$BINARY"
success "$BINARY is now vendored ☮"
} }
require_docker_version (){ require_jq() {
get_servers vendor_binary "https://github.com/stedolan/jq" "jq-1.6" "jq-linux64"
}
MIN_DOCKER_VERSION=19 require_yq() {
vendor_binary "https://github.com/mikefarah/yq" "v4.6.1" "yq_linux_amd64"
}
SERVERS+=("default") checkout_main_or_master() {
git checkout main > /dev/null 2>&1 || git checkout master > /dev/null 2>&1
for SERVER in "${SERVERS[@]}"; do
SERVER="${SERVER##*/}" # basename
host=$(docker context inspect "$SERVER" -f "{{.Endpoints.docker.Host}}" 2>/dev/null)
if [[ -n "$host" ]]; then
major_version=$(DOCKER_CONTEXT="$SERVER" docker version --format "{{.Server.Version}}" | cut -d'.' -f1 2>/dev/null)
if [[ "$major_version" -lt "$MIN_DOCKER_VERSION" ]]; then
error "This tool requires Docker v${MIN_DOCKER_VERSION} or greater. Please upgrade your Docker installation on $SERVER"
exit 1
else
debug "Docker version on $SERVER is sufficient (v${major_version})"
fi
fi
done
} }
# FIXME 3wc: update or remove # FIXME 3wc: update or remove
@ -554,21 +622,33 @@ if [ -z "$ABRA_ENV" ] && [ -f .env ] && type direnv > /dev/null 2>&1 && ! direnv
error "direnv is blocked, run direnv allow" error "direnv is blocked, run direnv allow"
fi fi
###### Parse apps.json
get_recipes() {
require_jq
mapfile -t RECIPES < <($JQ -r ". | keys | .[]" "$ABRA_APPS_JSON" | sort)
}
get_recipe_versions() {
require_jq
recipe="${1?Recipe not set}"
mapfile -t RECIPE_VERSIONS < <($JQ -r ".\"${recipe}\".versions | keys | .[]" "$ABRA_APPS_JSON" | sort)
}
###### Run-time loading ###### Run-time loading
load_abra_sh() { load_abra_sh() {
if [ -f abra.sh ]; then if [ -f abra.sh ]; then
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source abra.sh source abra.sh
info "Loading abra.sh" debug "Loading ./abra.sh"
fi
if [ -n "$abra__app_" ]; then
require_app_latest "$TYPE"
fi fi
if [ -f "$APP_DIR/abra.sh" ]; then if [ -f "$APP_DIR/abra.sh" ]; then
info "Loading $APP_DIR/abra.sh" debug "Loading $APP_DIR/abra.sh"
# shellcheck disable=SC1090,SC1091 # shellcheck disable=SC1090,SC1091
source "$APP_DIR/abra.sh" source "$APP_DIR/abra.sh"
fi fi
@ -622,7 +702,7 @@ output_version_summary() {
if [ "$live_version" != "$service_tag" ] || [ "$live_digest" != "$service_digest" ]; then if [ "$live_version" != "$service_tag" ] || [ "$live_digest" != "$service_digest" ]; then
IS_AN_UPDATE="true" IS_AN_UPDATE="true"
fi fi
echo " to be deployed: $(tput setaf 1)$service_version ($service_digest)$(tput sgr0)" echo " to be deployed: $(tput setaf 1)$service_tag ($service_digest)$(tput sgr0)"
fi fi
else else
if [[ $UNDEPLOYED_STATE == "true" ]]; then if [[ $UNDEPLOYED_STATE == "true" ]]; then
@ -989,7 +1069,10 @@ sub_app_new (){
DOMAIN=$abra___domain DOMAIN=$abra___domain
APP_NAME=$abra___app_name APP_NAME=$abra___app_name
require_app_latest "$TYPE" get_recipe_versions "$TYPE"
VERSION="${RECIPE_VERSIONS[-1]}"
require_app_version "$TYPE" "$VERSION"
if [ -z "$SERVER" ]; then if [ -z "$SERVER" ]; then
echo "Where would you like to put $TYPE?" echo "Where would you like to put $TYPE?"
@ -1065,8 +1148,6 @@ sub_app_new (){
###### .. app backup ###### .. app backup
sub_app_backup (){ sub_app_backup (){
require_app_latest "$TYPE"
# Add _<service> if it's defined # Add _<service> if it's defined
FUNCTION="abra_backup${abra__service_:+_}$abra__service_" FUNCTION="abra_backup${abra__service_:+_}$abra__service_"
@ -1082,8 +1163,6 @@ sub_app_backup (){
###### .. app restore ###### .. app restore
sub_app_restore (){ sub_app_restore (){
require_app_latest "$TYPE"
FUNCTION="abra_restore_$abra__service_" FUNCTION="abra_restore_$abra__service_"
if ! type "$FUNCTION" > /dev/null 2>&1; then if ! type "$FUNCTION" > /dev/null 2>&1; then
@ -1163,13 +1242,14 @@ _abra_backup_mysql() {
###### .. app deploy ###### .. app deploy
help_app_deploy (){ help_app_deploy (){
echo "abra [options] app <app> deploy [--update] echo "abra [options] app <app> deploy [--update] [--force] [--skip-version-check]
Deploy app <app> to the configured server. Deploy app <app> to the configured server.
OPTIONS OPTIONS
--update Consent to deploying an updated app version --update Consent to deploying an updated app version
--force Force a deployment regardless of state --force Force a deployment regardless of state
--skip-version-check Don't try and detect deployed version
POWERED BY POWERED BY
docker stack deploy -c compose.yml <app>" docker stack deploy -c compose.yml <app>"
@ -1177,11 +1257,24 @@ POWERED BY
sub_app_deploy (){ sub_app_deploy (){
require_yq require_yq
require_app_latest "$TYPE"
NON_INTERACTIVE=$abra___no_prompt NON_INTERACTIVE=$abra___no_prompt
SKIP_VERSION_CHECK=$abra___skip_version_check SKIP_VERSION_CHECK=$abra___skip_version_check
if [ -n "$abra__version_" ]; then
VERSION="$abra__version_"
if ! printf '%s\0' "${RECIPE_VERSIONS[@]}" | grep -Fqxz -- "$VERSION"; then
error "'$version' doesn't appear to be a valid version of $TYPE"
fi
else
get_recipe_versions "$TYPE"
VERSION="${RECIPE_VERSIONS[-1]}"
fi
info "Chose version $VERSION"
require_app_version "$TYPE" "$VERSION"
echo "Deployment overview:" echo "Deployment overview:"
echo " Server: $(tput setaf 4)${SERVER}$(tput sgr0)" echo " Server: $(tput setaf 4)${SERVER}$(tput sgr0)"
@ -1609,22 +1702,41 @@ sub_app_run(){
###### .. app rollback ###### .. app rollback
help_app_rollback (){ help_app_rollback (){
echo "abra [options] app <app> rollback <service> echo "abra [options] app <app> rollback [<version>]
Rollback a deployed app service to a previous version. Roll back a deployed app to a previous version.
You can specify a particular <version>; see \`abra recipe <recipe> version\` for
the list of options.
Otherwise, we'll roll back to the second-most-recent available version.
EXAMPLES EXAMPLES
abra app wordpress rollback app abra app wordpress rollback
POWERED BY POWERED BY
CONTAINER_ID=\$(docker container ls -f ...) abra app <app> deploy <version> --update"
docker service rollback \$CONTAINER_ID ..."
} }
sub_app_rollback(){ sub_app_rollback(){
SERVICE="${abra__service_}" version="${abra__version_}"
docker service rollback "${STACK_NAME}_${SERVICE}" get_recipe_versions "$TYPE"
if [ "${#RECIPE_VERSIONS[@]}" -lt 2 ]; then
error "Can't roll back; need 2 versions, ${#RECIPE_VERSIONS[@]} available"
fi
if [ -z "$version" ]; then
version="${RECIPE_VERSIONS[-2]}"
info "Guessed version $version"
fi
# FIXME 3wc: check if $version is actually older than what's deployed
abra__version_="$version"
abra___update="true"
sub_app_deploy
} }
###### .. app logs ###### .. app logs
@ -1726,6 +1838,203 @@ sub_app_cp() {
docker cp ${CP_ARGS} docker cp ${CP_ARGS}
} }
#######################################
# abra recipe ..
#######################################
###### .. recipe ls
help_recipe_ls (){
help_recipe_list
}
sub_recipe_ls() {
sub_recipe_list
}
help_recipe_list() {
echo "abra [options] recipe (list|ls)
List all available recipes."
}
sub_recipe_list() {
get_recipes
printf "%s delicious recipes:\n" "${#RECIPES[@]}"
printf '%s\n' "${RECIPES[@]}"
}
###### .. recipe <recipe> versions
help_recipe_versions() {
echo "abra [options] recipe versions
Show all available versions of <recipe>."
}
sub_recipe_versions() {
get_recipe_versions "$abra__recipe_"
printf "%s thrilling versions of $abra__recipe_:\n" "${#RECIPE_VERSIONS[@]}"
for version in "${RECIPE_VERSIONS[@]}"; do
recipe_version_data=$($JQ -r ".\"${abra__recipe_}\".versions.\"${version}\"" "$ABRA_APPS_JSON")
mapfile -t services < <(echo "$recipe_version_data" | $JQ -r ". | keys | .[]" -)
printf '%s:\n' "$version"
for service in "${services[@]}"; do
image=$(echo "$recipe_version_data" | $JQ -r ".$service.image" -)
tag=$(echo "$recipe_version_data" | $JQ -r ".$service.tag" -)
digest=$(echo "$recipe_version_data" | $JQ -r ".$service.digest" -)
printf ' - %s (%s:%s, %s)\n' "$service" "$image" "$tag" "$digest"
done
done
}
###### .. recipe <recipe> release
help_recipe_release() {
echo "abra [options] recipe <recipe> release
(For recipe maintainers)
Make sure the service labels and git tags for <recipe> are in sync with the
specified image tags.
Run this after you or comrade \`renovate-bot\` have bumped the version of
any of the images in <recipe>.
OPTIONS
--force Over-write existing tag; use this if you have a git tag for the
recipe version already, to make sure labels are in sync.
POWERED BY
skopeo inspect docker://image:tag
git commit
git tag"
}
sub_recipe_release() {
require_binary skopeo
require_yq
recipe="$abra__recipe_"
force="$abra___force"
recipe_dir="$ABRA_DIR/apps/$recipe"
cd "$recipe_dir" || error "Can't find recipe dir '$recipe_dir'"
get_recipe_versions "$recipe"
if [ "${#RECIPE_VERSIONS[@]}" -gt 0 ]; then
latest_version="${RECIPE_VERSIONS[-1]}"
latest_version_message=$(git tag -l "$latest_version" --format='%(contents)')
info "Latest available version: '$latest_version'"
else
latest_version=""
latest_version_message="Initial tagged release"
info "No previous releases found"
fi
current_tag=$(git tag --points-at HEAD)
if [ "$force" = "false" ] && [ -n "$current_tag" ]; then
error "$recipe is already on $current_tag, no release needed"
fi
if [ "$(git rev-parse --abbrev-ref --symbolic-full-name HEAD)" = "HEAD" ]; then
warning "It looks like $recipe_dir is in 'detached HEAD' state"
read -rp "Check out main/master branch first? [Y/n] "
if [ "${choice,,}" != "n" ]; then
checkout_main_or_master
fi
fi
mapfile -t extra_compose_files < <(ls -- compose.*.yml 2> /dev/null || true)
compose_files=("compose.yml" "${extra_compose_files[@]}")
new_version="false"
for compose_file in "${compose_files[@]}"; do
mapfile -t services < <($YQ e -N '.services | keys | .[]' "$compose_file" | sort -u)
for service in "${services[@]}"; do
# 3wc: skip the "app" service unless we're in compose.yml; this service is
# often repeated in other compose.*.yml files to extend options, but we only
# want to add the deploy.label in one definition
# TODO 3wc: make this smarter, what if a separate compose file extends
# other services too?
if [ "$compose_file" != "compose.yml" ] && [ "$service" = "app" ]; then
debug "Skipping '$service'"
continue
fi
debug "Processing '$service'"
service_image=$($YQ e ".services.$service.image" "$compose_file")
service_tag="${service_image##*:}"
if [ -n "$latest_version" ]; then
latest_data=$($JQ ".\"$recipe\".versions.\"$latest_version\".\"$service\"" "$ABRA_APPS_JSON")
latest_tag="$(echo "$latest_data" | $JQ -r ".tag" -)"
fi
if [ -z "$latest_version" ] || [ "$force" = "true" ] || [ "$service_tag" != "$latest_tag" ]; then
if [ "$service" = "app" ]; then
new_version="$service_tag"
fi
info "Fetching $service_image metadata from Docker Hub"
service_data=$(skopeo inspect "docker://$service_image")
service_digest=$(echo "$service_data" | jq -r '.Digest' | cut -d':' -f2 | cut -c-8)
label="coop-cloud.\${STACK_NAME}.$service.version=${service_tag}-${service_digest}"
debug "Replacing version label on $service with $label"
# delete old label, if one exists
$YQ eval -i "del(.services.$service.deploy.labels.[] | select(. == \"coop*\"))" "$compose_file"
# add new label
$YQ eval -i ".services.$service.deploy.labels += [\"$label\"]" "$compose_file"
else
debug "no updates for '$service_image'"
fi
done
done
if [ "$new_version" = "false" ]; then
# `app` tag hasn't changed, just bump release
if echo "$latest_version" | grep -q '_'; then
latest_version_minor="${latest_version##*_}"
else
latest_version_minor=0
fi
new_version_minor="$((latest_version_minor + 1))"
new_version="${latest_version%%*_}_$new_version_minor"
fi
debug "Calculated new version $new_version"
if [ -n "$latest_version" ] && [ "$force" = "false" ] && [ "$new_version" = "$latest_version" ]; then
error "Hmm, something went wrong generating a new version number.."
fi
success "All compose files updated; new version is $new_version"
read -rp "Commit your changes to git? (y/[n])? " choice
if [ "${choice,,}" != "y" ]; then
return
fi
git commit -avem "Version $new_version; sync labels" || exit
read -rp "Tag this as \`$new_version\`? (y/[n])? " choice
if [ "${choice,,}" != "y" ]; then
return
fi
test "$force" = "true" && git tag -d "$new_version"
git tag -aem "$latest_version_message" "$new_version"
}
####################################### #######################################
# abra server .. # abra server ..
####################################### #######################################
@ -2013,7 +2322,7 @@ abra() {
abra___skip_check abra__backup_file_ abra___verbose abra___debug \ abra___skip_check abra__backup_file_ abra___verbose abra___debug \
abra___help abra___branch abra___volumes abra__provider_ abra___type \ abra___help abra___branch abra___volumes abra__provider_ abra___type \
abra___dev abra___update abra___no_prompt abra___force \ abra___dev abra___update abra___no_prompt abra___force \
abra___skip_version_check abra___skip_version_check abra__recipe_
if ! type tput > /dev/null 2>&1; then if ! type tput > /dev/null 2>&1; then
tput() { tput() {
@ -2039,6 +2348,7 @@ abra() {
if [ -n "$abra__app_" ]; then if [ -n "$abra__app_" ]; then
load_instance load_instance
load_instance_env load_instance_env
require_apps_json
fi fi
load_abra_sh load_abra_sh

View File

@ -13,7 +13,7 @@ from os.path import basename, exists, expanduser
from pathlib import Path from pathlib import Path
from re import findall, search from re import findall, search
from shlex import split from shlex import split
from subprocess import check_output from subprocess import check_output, DEVNULL
from sys import exit from sys import exit
from requests import get from requests import get
@ -31,6 +31,8 @@ REPOS_TO_SKIP = (
"organising", "organising",
"pyabra", "pyabra",
"stack-ssh-deploy", "stack-ssh-deploy",
"radicle-seed-node",
"coturn"
) )
log = getLogger(__name__) log = getLogger(__name__)
@ -38,10 +40,9 @@ basicConfig()
log.setLevel(DEBUG) log.setLevel(DEBUG)
def _run_cmd(cmd, shell=False): def _run_cmd(cmd, shell=False, **kwargs):
"""Run a shell command.""" """Run a shell command."""
args = [split(cmd)] args = [split(cmd)]
kwargs = {}
if shell: if shell:
args = [cmd] args = [cmd]
@ -187,7 +188,8 @@ def get_app_versions(app_path, cached_apps_json):
existing_tags = [] existing_tags = []
for tag in tags: for tag in tags:
_run_cmd(f"git checkout {tag}") _run_cmd(f"git checkout {tag}",
stderr=DEVNULL)
services_cmd = f"{YQ_PATH} e '.services | keys | .[]' compose*.yml" services_cmd = f"{YQ_PATH} e '.services | keys | .[]' compose*.yml"
services = _run_cmd(services_cmd, shell=True).split() services = _run_cmd(services_cmd, shell=True).split()

View File

@ -1,76 +0,0 @@
#!/bin/bash
# Usage: ./app-version.sh app-directory
#
# Pull image tag versions and digests into each recipe's compose.yml file, and
# update git tags to point to the new ref
YQ="$HOME/.abra/vendor/yq"
function process_file() {
compose_file="${1?Compose file not set}"
mapfile -t services < <($YQ e -N '.services | keys | .[]' "$compose_file" | sort -u)
for service in "${services[@]}"; do
# 3wc: skip the "app" service unless we're in compose.yml; this service is
# often repeated in other compose.*.yml files to extend options, but we only
# want to add the deploy.label in one definition
# TODO 3wc: make this smarter, what if a separate compose file extends
# other services too?
if [ "$compose_file" != "compose.yml" ] && [ "$service" = "app" ]; then
echo "debug: skipping $service"
continue
fi
echo "debug: processing $service"
service_data=$(jq ".$app.versions.\"$latest_version\".$service" ~/.abra/apps.json)
service_tag=$(echo "$service_data" | jq -r '.tag')
service_digest=$(echo "$service_data" | jq -r '.digest')
label="coop-cloud.\${STACK_NAME}.$service.version=${service_tag}-${service_digest}"
# delete old label, if one exists
$YQ eval -i "del(.services.$service.deploy.labels.[] | select(. == \"coop*\"))" "$compose_file"
# add new label
$YQ eval -i ".services.$service.deploy.labels += [\"$label\"]" "$compose_file"
done
}
stack_dir="${ABRA_DIR:-$HOME/.abra}/apps/"
app="${1?No app provided}"
cd "$stack_dir/$app" || exit
mapfile -t extra_compose_files < <(ls -- compose.*.yml || true)
compose_files=("compose.yml" "${extra_compose_files[@]}")
mapfile -t git_tags < <(git tag -l)
latest_version="${git_tags[-1]}"
latest_version_message=$(git tag -l "$latest_version" --format='%(contents)')
echo "debug: latest version: $latest_version"
for compose_file in "${compose_files[@]}"; do
process_file "$compose_file"
done
read -rp "On the next screen, you'll see the proposed changes; press 'q' to exit when you're done. Hit 'return' / 'enter' to continue now" choice
git diff
read -rp "Commit this change and replace the '$latest_version' tag? (y/[n])? " choice
if [ "${choice,,}" != "y" ]; then
exit
fi
git commit -a -m "Auto-add service labels"
git tag -d "$latest_version"
git tag -a "$latest_version" -m "$latest_version_message"