From a261114bbc7519195a420e8f0a246265ad10bc72 Mon Sep 17 00:00:00 2001 From: 3wc <3wc.git@doesthisthing.work> Date: Sun, 4 Apr 2021 23:35:13 +0200 Subject: [PATCH] Add --force to `recipe .. release` --- abra | 128 +++++++++++++++++++++++++-------------------- bin/app-version.sh | 76 --------------------------- 2 files changed, 70 insertions(+), 134 deletions(-) delete mode 100755 bin/app-version.sh diff --git a/abra b/abra index 0ce6491..39fd37a 100755 --- a/abra +++ b/abra @@ -36,7 +36,7 @@ Usage: abra [options] app undeploy abra [options] app [...] abra [options] recipe ls - abra [options] recipe release + abra [options] recipe release [--force] abra [options] recipe versions abra [options] server add [] [] abra [options] server new @@ -163,30 +163,29 @@ 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() { printf -- "cat <<'EOM' >&2\n%s\nEOM\n" "$1"; }; error() { [[ -n $1 ]] && stderr "$1"; stderr "$usage"; _return 1; }; _return() { -printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:2286} -usage=${DOC:40:1677}; digest=07a57 -shorts=(-h -s -U -e -b -v -C -d -n '' '' '' '' '' '' '' '' '' '' '' '' '' '' '') -longs=(--help --stack --skip-update --env --branch --verbose --skip-check --debug --no-prompt --status --server --type --domain --app-name --pass --secrets --all --update --force --skip-version-check --volumes --no-tty --user --dev) -argcounts=(0 1 0 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0); node_0(){ -switch __help 0; }; node_1(){ value __stack 1; }; node_2(){ -switch __skip_update 2; }; node_3(){ value __env 3; }; node_4(){ -value __branch 4; }; node_5(){ switch __verbose 5; }; node_6(){ -switch __skip_check 6; }; node_7(){ switch __debug 7; }; node_8(){ -switch __no_prompt 8; }; node_9(){ switch __status 9; }; node_10(){ -value __server 10; }; node_11(){ value __type 11; }; node_12(){ -value __domain 12; }; node_13(){ value __app_name 13; }; node_14(){ -switch __pass 14; }; node_15(){ switch __secrets 15; }; node_16(){ -switch __all 16; }; node_17(){ switch __update 17; }; node_18(){ -switch __force 18; }; node_19(){ 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; }; node_24(){ value _type_ a; } -node_25(){ value _app_ a; }; node_26(){ value _service_ a; }; node_27(){ -value _version_ a; }; node_28(){ value _src_ a; }; node_29(){ value _dst_ a; } -node_30(){ value _backup_file_ a; }; node_31(){ value _args_ a true; } -node_32(){ value _secret_ a; }; node_33(){ value _cmd_ a; }; node_34(){ -value _data_ a; }; node_35(){ value _command_ a; }; node_36(){ value _recipe_ a -}; node_37(){ value _host_ a; }; node_38(){ value _user_ a; }; node_39(){ -value _port_ a; }; node_40(){ value _provider_ a; }; node_41(){ +printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:2296} +usage=${DOC:40:1687}; digest=4e473 +shorts=(-e -d -b -n -v -s -C -U -h '' '' '' '' '' '' '' '' '' '' '' '' '' '' '') +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=(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(){ +value __env 0; }; node_1(){ switch __debug 1; }; node_2(){ value __branch 2; } +node_3(){ switch __no_prompt 3; }; node_4(){ switch __verbose 4; }; node_5(){ +value __stack 5; }; node_6(){ switch __skip_check 6; }; node_7(){ +switch __skip_update 7; }; node_8(){ switch __help 8; }; node_9(){ +switch __status 9; }; node_10(){ value __server 10; }; node_11(){ +value __type 11; }; node_12(){ value __domain 12; }; node_13(){ +value __app_name 13; }; node_14(){ switch __pass 14; }; node_15(){ +switch __secrets 15; }; node_16(){ switch __all 16; }; node_17(){ +switch __update 17; }; node_18(){ switch __force 18; }; node_19(){ +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 +}; node_24(){ value _type_ a; }; node_25(){ value _app_ a; }; node_26(){ +value _service_ a; }; node_27(){ value _version_ a; }; node_28(){ value _src_ a +}; node_29(){ value _dst_ a; }; node_30(){ value _backup_file_ a; }; node_31(){ +value _args_ a true; }; node_32(){ value _secret_ a; }; node_33(){ value _cmd_ a +}; node_34(){ value _data_ a; }; node_35(){ value _command_ a; }; node_36(){ +value _recipe_ a; }; node_37(){ value _host_ a; }; node_38(){ value _user_ a; } +node_39(){ value _port_ a; }; node_40(){ value _provider_ a; }; node_41(){ value _subcommands_ a true; }; node_42(){ _command app; }; node_43(){ _command list; }; node_44(){ _command ls; }; node_45(){ _command new; } node_46(){ _command backup; }; node_47(){ _command deploy; }; node_48(){ @@ -225,7 +224,7 @@ required 74 42 25 59 61 32 27 34 83; }; node_119(){ either 32 16; }; node_120(){ required 119; }; node_121(){ required 74 42 25 59 103 120 83; }; node_122(){ required 74 42 25 62; }; node_123(){ optional 110; }; node_124(){ required 74 42 25 35 123; }; node_125(){ required 74 63 44; }; node_126(){ -required 74 63 36 64; }; node_127(){ required 74 63 36 65; }; node_128(){ +required 74 63 36 64 90; }; node_127(){ required 74 63 36 65; }; node_128(){ optional 38; }; node_129(){ optional 39; }; node_130(){ required 74 66 67 37 128 129; }; node_131(){ required 74 66 45 40; } node_132(){ required 74 66 76; }; node_133(){ required 74 66 37 55; } @@ -236,9 +235,9 @@ node_141(){ optional 140; }; node_142(){ required 74 72 141; }; node_143(){ 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:1677}" >&2 -exit 1; }'; unset var___help var___stack var___skip_update var___env \ -var___branch var___verbose var___skip_check var___debug var___no_prompt \ +[[ -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___secrets var___all var___update var___force var___skip_version_check \ var___volumes var___no_tty var___user var___dev var__type_ var__app_ \ @@ -249,10 +248,10 @@ var_new var_backup var_deploy var_check var_version var_config var_cp var_logs \ var_ps var_restore var_rm var_delete var_run var_rollback var_secret \ var_generate var_insert var_undeploy var_recipe var_release var_versions \ var_server var_add var_init var_apps var_upgrade var_doctor var_help -parse 145 "$@"; local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__help" \ -"${prefix}__stack" "${prefix}__skip_update" "${prefix}__env" \ -"${prefix}__branch" "${prefix}__verbose" "${prefix}__skip_check" \ -"${prefix}__debug" "${prefix}__no_prompt" "${prefix}__status" \ +parse 145 "$@"; local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__env" \ +"${prefix}__debug" "${prefix}__branch" "${prefix}__no_prompt" \ +"${prefix}__verbose" "${prefix}__stack" "${prefix}__skip_check" \ +"${prefix}__skip_update" "${prefix}__help" "${prefix}__status" \ "${prefix}__server" "${prefix}__type" "${prefix}__domain" \ "${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \ "${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \ @@ -269,15 +268,15 @@ parse 145 "$@"; local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__help" \ "${prefix}generate" "${prefix}insert" "${prefix}undeploy" "${prefix}recipe" \ "${prefix}release" "${prefix}versions" "${prefix}server" "${prefix}add" \ "${prefix}init" "${prefix}apps" "${prefix}upgrade" "${prefix}doctor" \ -"${prefix}help"; eval "${prefix}"'__help=${var___help:-false}' -eval "${prefix}"'__stack=${var___stack:-}' -eval "${prefix}"'__skip_update=${var___skip_update:-false}' -eval "${prefix}"'__env=${var___env:-}' -eval "${prefix}"'__branch=${var___branch:-}' -eval "${prefix}"'__verbose=${var___verbose:-false}' -eval "${prefix}"'__skip_check=${var___skip_check:-false}' +"${prefix}help"; eval "${prefix}"'__env=${var___env:-}' eval "${prefix}"'__debug=${var___debug:-false}' +eval "${prefix}"'__branch=${var___branch:-}' eval "${prefix}"'__no_prompt=${var___no_prompt:-false}' +eval "${prefix}"'__verbose=${var___verbose:-false}' +eval "${prefix}"'__stack=${var___stack:-}' +eval "${prefix}"'__skip_check=${var___skip_check:-false}' +eval "${prefix}"'__skip_update=${var___skip_update:-false}' +eval "${prefix}"'__help=${var___help:-false}' eval "${prefix}"'__status=${var___status:-false}' eval "${prefix}"'__server=${var___server:-}' eval "${prefix}"'__type=${var___type:-}' @@ -340,9 +339,9 @@ eval "${prefix}"'upgrade=${var_upgrade:-false}' eval "${prefix}"'doctor=${var_doctor:-false}' eval "${prefix}"'help=${var_help:-false}'; local docopt_i=1 [[ $BASH_VERSION =~ ^4.3 ]] && docopt_i=2; for ((;docopt_i>0;docopt_i--)); do -declare -p "${prefix}__help" "${prefix}__stack" "${prefix}__skip_update" \ -"${prefix}__env" "${prefix}__branch" "${prefix}__verbose" \ -"${prefix}__skip_check" "${prefix}__debug" "${prefix}__no_prompt" \ +declare -p "${prefix}__env" "${prefix}__debug" "${prefix}__branch" \ +"${prefix}__no_prompt" "${prefix}__verbose" "${prefix}__stack" \ +"${prefix}__skip_check" "${prefix}__skip_update" "${prefix}__help" \ "${prefix}__status" "${prefix}__server" "${prefix}__type" "${prefix}__domain" \ "${prefix}__app_name" "${prefix}__pass" "${prefix}__secrets" "${prefix}__all" \ "${prefix}__update" "${prefix}__force" "${prefix}__skip_version_check" \ @@ -1902,19 +1901,29 @@ sub_recipe_release() { require_yq recipe="$abra__recipe_" + force="$abra___force" recipe_dir="$ABRA_DIR/apps/$recipe" - get_recipe_versions "$recipe" - latest_version="${RECIPE_VERSIONS[-1]}" - 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="" + info "No previous releases found" + fi + current_tag=$(git tag --points-at HEAD) - if [ -n "$current_tag" ]; then + if [ "$force" = "false" ] && [ -n "$current_tag" ]; then error "$recipe is already on $current_tag, no release needed" fi - mapfile -t extra_compose_files < <(ls -- compose.*.yml || true) + mapfile -t extra_compose_files < <(ls -- compose.*.yml 2> /dev/null || true) compose_files=("compose.yml" "${extra_compose_files[@]}") @@ -1930,22 +1939,24 @@ sub_recipe_release() { # 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'" + debug "Skipping '$service'" continue fi - debug "processing '$service'" + debug "Processing '$service'" service_image=$($YQ e ".services.$service.image" "$compose_file") service_tag="${service_image##*:}" - latest_data=$($JQ ".$recipe.versions.\"$latest_version\".\"$service\"" "$ABRA_APPS_JSON") - latest_tag="$(echo "$latest_data" | $JQ -r ".tag" -)" + 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 [ "$service_tag" != "$latest_tag" ]; then + 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" + 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) @@ -1958,7 +1969,7 @@ sub_recipe_release() { # add new label $YQ eval -i ".services.$service.deploy.labels += [\"$label\"]" "$compose_file" else - debug "no updates for $service" + debug "no updates for '$service_image'" fi done done @@ -1976,7 +1987,7 @@ sub_recipe_release() { debug "Calculated new version $new_version" - if [ "$new_version" = "$latest_version" ]; then + if [ -n "$latest_version" ] && [ "$force" = "false" ] && [ "$new_version" = "$latest_version" ]; then error "Hmm, something went wrong generating a new version number.." fi @@ -1988,7 +1999,7 @@ sub_recipe_release() { return fi - git commit -av || exit + git commit -avem "Version $new_version; sync labels" || exit read -rp "Tag this as \`$new_version\`? (y/[n])? " choice @@ -1996,7 +2007,8 @@ sub_recipe_release() { return fi - git tag -a "$new_version" + test "$force" = "true" && git tag -d "$new_version" + git tag -aem "$latest_version_message" "$new_version" } ####################################### diff --git a/bin/app-version.sh b/bin/app-version.sh deleted file mode 100755 index 37b070d..0000000 --- a/bin/app-version.sh +++ /dev/null @@ -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"