yage
a739d3b5a2
===================================================================== Big day! V4 is finally live. This INCLUDES some BREAKING CHANGES to ZSH TYPE scwrypts! Please refer to the readme for upgrade details (more specifically docs/upgrade/v3-to-v4.md) Upgrade is SUPER EASY, so please take the time to do so. --- New Features ---------------------------------------------------- - zsh type scwrypts have an upgraded runstring to improve context setup and simplicity to the scwrypt-writer - scwrypts now publishes the package (scwrypts) to PyPi; this provides a simple way to invoke scwrypts from python-based environments as well as the entire scwrypts python library suite pip install scwrypts - scwrypts now publishes the package (scwrypts) to npm; this provides a simple way to invoke scwrypts from nodesjs environments npm install scwrypts --- Bug Fixes ------------------------------------------------------- - scwrypts runner prompts which use the zshbuiltin "read" now appropriately read input from tty, pipe, files, and user input - virtualenv refresh now loads and prepares the scwrypts virtual environments correctly --- Changes --------------------------------------------------------- - created the (-v, --log-level) scwrypts arguments as improvements of and replacements to the --verbose and --no-log flags - (-n) is now an alias for (--log-level 0) - (--no-log) is the same as (-n) for compatibility, but will be removed in 4.2 - zsh/lib/utils/io print functions now *interact with log-level* various log levels will now only display the appropriate console prints for the specified log level - zsh/lib/utils/io:INFO has been renamed to DEBUG to align with log-level output; please use DEBUG for debug messages and REMINDER for important user messages - created zsh/lib/utils/io:FZF_USER_INPUT as a *drop-in replacement* for the confusing FZF_HEAD and FZF_TAIL commands. Update by literally changing any instances of FZF_HEAD or FZF_TAIL with FZF_USER_INPUT - FZF_HEAD and FZF_TAIL will be removed in 4.2 - zsh/lib/utils/io:READ (and other zshbuiltin/read-based prompts) now accept a --force-user-input flag in case important checks should require an admin's approval. This flag will ensure that piped input and the `scwrypts -y` flag are ignored for the single prompt. - zsh/lib/utils/color has been updated to use color names which match the ANSI color names - zsh/hello-world has been reduced to a minimal example; this is to emphasize ease-of-use with v4 - zsh/sanity-check is a scwrypts/run testing helper and detailed starting reference (helpful since hello-world is now minimal) - various refactor, updates, and improvements to the scwrypts runner - migrated all zsh scwrypts and plugins to use v4 runner syntax - zsh - plugins/kubectl - plugins/ci - refactored py/lib into py/lib/scwrypts (PyPi)
389 lines
11 KiB
Bash
Executable File
389 lines
11 KiB
Bash
Executable File
#!/bin/zsh
|
|
export EXECUTION_DIR=$(pwd)
|
|
source "${0:a:h}/zsh/lib/import.driver.zsh" || exit 42
|
|
#####################################################################
|
|
() {
|
|
cd "$SCWRYPTS_ROOT__scwrypts"
|
|
GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; }
|
|
local ERRORS=0
|
|
local USAGE='
|
|
usage: scwrypts [...options...] [...patterns...] -- [...script options...]
|
|
|
|
options:
|
|
selection
|
|
-m, --name <scwrypt-name> only run the script if there is an exact match
|
|
(requires type and group)
|
|
-g, --group <group-name> only use scripts from the indicated group
|
|
-t, --type <type-name> only use scripts of the indicated type
|
|
|
|
runtime
|
|
-y, --yes auto-accept all [yn] prompts through current scwrypt
|
|
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
|
|
-n shorthand for "--log-level 0"
|
|
-v, --log-level [0-4] set scwrypts log level to one of the following:
|
|
0 : only command output and critical failures; skips logfile
|
|
1 : add success / failure messages
|
|
2 : (default) include status update messages
|
|
3 : (CI default) include warning messages
|
|
4 : include debug messages
|
|
|
|
alternate commands
|
|
-h, --help display this message and exit
|
|
-l, --list print out command list and exit
|
|
--list-envs print out environment list and exit
|
|
--update update scwrypts library to latest version
|
|
--version print out scwrypts version and exit
|
|
|
|
patterns:
|
|
- a list of glob patterns to loose-match a scwrypt by name
|
|
|
|
script options:
|
|
- everything after "--" is forwarded to the scwrypt you run
|
|
("-- --help" will provide more information)
|
|
'
|
|
|
|
#####################################################################
|
|
### cli argument parsing and global configuration ###################
|
|
#####################################################################
|
|
|
|
local ENV_NAME="$SCWRYPTS_ENV"
|
|
local SEARCH_PATTERNS=()
|
|
|
|
local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME
|
|
|
|
[ ! $SCWRYPTS_LOG_LEVEL ] && {
|
|
local SCWRYPTS_LOG_LEVEL
|
|
[ $CI ] && SCWRYPTS_LOG_LEVEL=3 || SCWRYPTS_LOG_LEVEL=2
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]
|
|
do
|
|
case $1 in
|
|
-[a-z][a-z]* )
|
|
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
|
|
set -- $(echo " $VARSPLIT ") ${@:2}
|
|
;;
|
|
|
|
### alternate commands ###################
|
|
|
|
-h | --help )
|
|
USAGE
|
|
return 0
|
|
;;
|
|
|
|
-l | --list )
|
|
SCWRYPTS__GET_AVAILABLE_SCWRYPTS
|
|
return 0
|
|
;;
|
|
|
|
--list-envs )
|
|
SCWRYPTS__GET_ENV_NAMES
|
|
return 0
|
|
;;
|
|
|
|
--version )
|
|
echo scwrypts $(GIT_SCWRYPTS describe --tags)
|
|
return 0
|
|
;;
|
|
|
|
--update )
|
|
GIT_SCWRYPTS fetch --quiet origin main
|
|
GIT_SCWRYPTS fetch --quiet origin main --tags
|
|
local SYNC_STATUS=$?
|
|
|
|
GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1
|
|
local DIFF_STATUS=$?
|
|
|
|
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
|
|
SUCCESS 'already up-to-date with origin/main'
|
|
} || {
|
|
GIT_SCWRYPTS rebase --autostash origin/main \
|
|
&& SUCCESS 'up-to-date with origin/main' \
|
|
&& GIT_SCWRYPTS log -n1 \
|
|
|| {
|
|
GIT_SCWRYPTS rebase --abort
|
|
ERROR 'unable to update scwrypts; please try manual upgrade'
|
|
REMINDER "installation in '$(pwd)'"
|
|
}
|
|
}
|
|
return 0
|
|
;;
|
|
|
|
### scwrypts filters #####################
|
|
|
|
-m | --name )
|
|
[ $2 ] || { ERROR "missing value for argument $1"; break; }
|
|
SEARCH_NAME=$2
|
|
shift 1
|
|
;;
|
|
|
|
-g | --group )
|
|
[ $2 ] || { ERROR "missing value for argument $1"; break; }
|
|
SEARCH_GROUP=$2
|
|
shift 1
|
|
;;
|
|
|
|
-t | --type )
|
|
[ $2 ] || { ERROR "missing value for argument $1"; break; }
|
|
SEARCH_TYPE=$2
|
|
shift 1
|
|
;;
|
|
|
|
### runtime settings #####################
|
|
|
|
-y | --yes ) export __SCWRYPTS_YES=1 ;;
|
|
|
|
-n | --no-log )
|
|
SCWRYPTS_LOG_LEVEL=0
|
|
[[ $1 =~ ^--no-log$ ]] && WARNING 'the --no-log flag is deprecated and will be removed in scwrypts v4.2'
|
|
;;
|
|
|
|
-v | --log-level )
|
|
[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$2'"
|
|
SCWRYPTS_LOG_LEVEL=$2
|
|
shift 1
|
|
;;
|
|
|
|
-e | --env )
|
|
[ $2 ] || { ERROR "missing value for argument $1"; break; }
|
|
|
|
[ $ENV_NAME ] && DEBUG 'overwriting session environment'
|
|
|
|
ENV_NAME="$2"
|
|
STATUS "using CLI environment '$ENV_NAME'"
|
|
shift 1
|
|
;;
|
|
|
|
##########################################
|
|
|
|
-- ) shift 1; break ;; # pass arguments after '--' to the scwrypt
|
|
--* ) ERROR "unrecognized argument '$1'" ;;
|
|
* ) SEARCH_PATTERNS+=($1) ;;
|
|
esac
|
|
shift 1
|
|
done
|
|
|
|
[ $SEARCH_NAME ] && {
|
|
[ $SEARCH_TYPE ] || ERROR '--name requires --type argument'
|
|
[ $SEARCH_GROUP ] || ERROR '--name requires --group argument'
|
|
}
|
|
|
|
CHECK_ERRORS
|
|
|
|
#####################################################################
|
|
### scwrypts selection / filtering ##################################
|
|
#####################################################################
|
|
|
|
local SCWRYPTS_AVAILABLE
|
|
SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS)
|
|
|
|
##########################################
|
|
|
|
[ $SEARCH_NAME ] && SCWRYPTS_AVAILABLE=$({
|
|
echo $SCWRYPTS_AVAILABLE | head -n1
|
|
echo $SCWRYPTS_AVAILABLE | sed -e 's/\x1b\[[0-9;]*m//g' | grep "^$SEARCH_NAME *$SEARCH_TYPE *$SEARCH_GROUP\$"
|
|
}) || {
|
|
[ $SEARCH_TYPE ] && {
|
|
SCWRYPTS_AVAILABLE=$(\
|
|
{
|
|
echo $SCWRYPTS_AVAILABLE | head -n1
|
|
echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* '
|
|
} \
|
|
| awk '{$2=""; print $0;}' \
|
|
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
|
|
| column -ts '^'
|
|
)
|
|
}
|
|
|
|
[ $SEARCH_GROUP ] && {
|
|
SCWRYPTS_AVAILABLE=$(
|
|
{
|
|
echo $SCWRYPTS_AVAILABLE | head -n1
|
|
echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/]*$'
|
|
} \
|
|
| awk '{$NF=""; print $0;}' \
|
|
| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g' \
|
|
| column -ts '^'
|
|
)
|
|
}
|
|
|
|
[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && {
|
|
POTENTIAL_ERROR+="\n PATTERNS : $SEARCH_PATTERNS"
|
|
local P
|
|
for P in ${SEARCH_PATTERNS[@]}
|
|
do
|
|
SCWRYPTS_AVAILABLE=$(
|
|
{
|
|
echo $SCWRYPTS_AVAILABLE | head -n1
|
|
echo $SCWRYPTS_AVAILABLE | grep $P
|
|
}
|
|
)
|
|
done
|
|
}
|
|
}
|
|
|
|
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -lt 2 ]] && {
|
|
FAIL 1 "$(echo "
|
|
no such scwrypt exists
|
|
NAME : '$SEARCH_NAME'
|
|
TYPE : '$SEARCH_TYPE'
|
|
GROUP : '$SEARCH_GROUP'
|
|
PATTERNS : '$SEARCH_PATTERNS'
|
|
" | sed "1d; \$d; /''$/d")"
|
|
}
|
|
|
|
##########################################
|
|
|
|
[[ $(echo $SCWRYPTS_AVAILABLE | wc -l) -eq 2 ]] \
|
|
&& SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | tail -n1) \
|
|
|| SCWRYPT_SELECTION=$(echo $SCWRYPTS_AVAILABLE | FZF "select a script to run" --header-lines 1) \
|
|
;
|
|
|
|
[ $SCWRYPT_SELECTION ] || exit 2
|
|
|
|
##########################################
|
|
|
|
local NAME TYPE GROUP
|
|
SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION
|
|
|
|
export SCWRYPT_NAME=$NAME
|
|
export SCWRYPT_TYPE=$TYPE
|
|
export SCWRYPT_GROUP=$GROUP
|
|
|
|
#####################################################################
|
|
### environment variables and configuration validation ##############
|
|
#####################################################################
|
|
|
|
local ENV_REQUIRED=true \
|
|
&& [ ! $CI ] \
|
|
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
|
|
&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \
|
|
|| ENV_REQUIRED=false
|
|
|
|
local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP)
|
|
|
|
[[ $ENV_REQUIRED =~ true ]] && {
|
|
[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV)
|
|
|
|
for GROUP in ${SCWRYPTS_GROUPS[@]}
|
|
do
|
|
local ENV_FILE=$(SCWRYPTS__GET_ENV_FILE "$ENV_NAME" "$GROUP")
|
|
source "$ENV_FILE" || FAIL 5 "missing or invalid environment '$GROUP/$ENV_NAME'"
|
|
|
|
for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP)
|
|
do
|
|
source "$f" || FAIL 5 "invalid static config '$f'"
|
|
done
|
|
done
|
|
|
|
export ENV_NAME
|
|
}
|
|
|
|
##########################################
|
|
|
|
[ $REQUIRED_ENVIRONMENT_REGEX ] && {
|
|
[[ $ENV_NAME =~ $REQUIRED_ENVIRONMENT_REGEX ]] \
|
|
|| FAIL 5 "group '$SCWRYPT_GROUP' requires current environment name to match '$REQUIRED_ENVIRONMENT_REGEX' (currently $ENV_NAME)"
|
|
}
|
|
|
|
##########################################
|
|
|
|
[ ! $SUBSCWRYPT ] && [[ $ENV_NAME =~ prod ]] && {
|
|
STATUS "on '$ENV_NAME'; checking diff against origin/main"
|
|
|
|
GIT_SCWRYPTS fetch --quiet origin main
|
|
local SYNC_STATUS=$?
|
|
|
|
GIT_SCWRYPTS diff --exit-code origin/main -- . >&2
|
|
local DIFF_STATUS=$?
|
|
|
|
[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && {
|
|
SUCCESS 'up-to-date with origin/main'
|
|
} || {
|
|
SCWRYPTS_LOG_LEVEL=3 WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $([[ $SYNC_STATUS -ne 0 ]] && echo 'I am unable to verify your scwrypts version')$([[ $DIFF_STATUS -ne 0 ]] && echo 'your scwrypts is out-of-date (diff listed above)')"
|
|
|
|
yN 'continue?' || {
|
|
REMINDER "you can use 'scwrypts --update' to quickly update scwrypts to latest"
|
|
ABORT
|
|
}
|
|
}
|
|
}
|
|
|
|
##########################################
|
|
|
|
local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP)
|
|
[ "$RUN_STRING" ] || return 42
|
|
|
|
#####################################################################
|
|
### logging and pretty header/footer setup ##########################
|
|
#####################################################################
|
|
|
|
local LOGFILE \
|
|
&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \
|
|
&& [ ! $SUBSCWRYPT ] \
|
|
&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \
|
|
&& [[ ! $SCWRYPT_NAME =~ interactive ]] \
|
|
&& LOGFILE="$SCWRYPTS_LOG_PATH/$(echo $GROUP/$TYPE/$NAME | sed 's/^\.\///; s/\//\%/g').log" \
|
|
|| LOGFILE='/dev/null' \
|
|
;
|
|
|
|
local RUN_MODE=normal
|
|
[[ $LOGFILE =~ ^/dev/null$ ]] && RUN_MODE=no-logfile
|
|
[[ $SCWRYPT_NAME =~ interactive ]] && RUN_MODE=interactive
|
|
|
|
local HEADER FOOTER
|
|
|
|
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && {
|
|
HEADER=$(
|
|
echo "
|
|
=====================================================================
|
|
script : $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME
|
|
run at : $(date)
|
|
config : $ENV_NAME
|
|
log level : $SCWRYPTS_LOG_LEVEL
|
|
\\033[1;33m--- SCWRYPT BEGIN ---------------------------------------------------\\033[0m
|
|
" | sed 's/^\s\+//; 1d'
|
|
)
|
|
|
|
FOOTER="\\033[1;33m--- SCWRYPT END ---------------------------------------------------\\033[0m"
|
|
}
|
|
|
|
[ $SUBSCWRYPT ] && {
|
|
HEADER="\\033[0;33m--- ($SUBSCWRYPT) BEGIN $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
|
|
FOOTER="\\033[0;33m--- ($SUBSCWRYPT) END $SCWRYPT_GROUP $SCWRYPT_TYPE $SCWRYPT_NAME ---"
|
|
}
|
|
|
|
#####################################################################
|
|
### run the scwrypt #################################################
|
|
#####################################################################
|
|
|
|
[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0
|
|
|
|
set -o pipefail
|
|
{
|
|
[ $HEADER ] && echo $HEADER
|
|
case $RUN_MODE in
|
|
normal )
|
|
(eval "$RUN_STRING $(printf "%q " "$@")")
|
|
EXIT_CODE=$?
|
|
;;
|
|
no-logfile )
|
|
eval "$RUN_STRING $(printf "%q " "$@")"
|
|
EXIT_CODE=$?
|
|
;;
|
|
interactive )
|
|
eval "$RUN_STRING $(printf "%q " "$@")" </dev/tty >/dev/tty 2>&1
|
|
EXIT_CODE=$?
|
|
;;
|
|
esac
|
|
[ $FOOTER ] && echo $FOOTER
|
|
[[ $EXIT_CODE -eq 0 ]] && EXIT_COLOR='32m' || EXIT_COLOR='31m'
|
|
|
|
[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \
|
|
&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m"
|
|
|
|
return $EXIT_CODE
|
|
} 2>&1 | tee --append "$LOGFILE"
|
|
|
|
} $@
|