=====================================================================

--- Changes ------------------------------

- kubectl driver updates; getting better, but still need to fix
  autocomplete in certain circumstances

- added -y|--yes flags to scwrypts to auto-accept user-prompts (use with
  caution)

- figured out the whole mikefarah/yq vs kislyuk/yq thing; use YQ for
  compatiblity

--- Bug fixes ----------------------------

- helm template generation now loads values in a more appropriate order
  which prevents overwrite by the wrong values file
This commit is contained in:
Wryn (yage) Wagner 2023-11-22 15:54:16 -07:00
parent a03885e8db
commit 72e831da33
14 changed files with 354 additions and 37 deletions

View File

@ -3,6 +3,7 @@
unalias k h >/dev/null 2>&1 unalias k h >/dev/null 2>&1
k() { _SCWRYPTS_KUBECTL_DRIVER kubectl $@; } k() { _SCWRYPTS_KUBECTL_DRIVER kubectl $@; }
h() { _SCWRYPTS_KUBECTL_DRIVER helm $@; } h() { _SCWRYPTS_KUBECTL_DRIVER helm $@; }
f() { _SCWRYPTS_KUBECTL_DRIVER flux $@; }
_SCWRYPTS_KUBECTL_DRIVER() { _SCWRYPTS_KUBECTL_DRIVER() {
@ -57,7 +58,7 @@ _SCWRYPTS_KUBECTL_DRIVER() {
" "
local USAGE__description=" local USAGE__description="
Provides 'k' (kubectl) and 'h' (helm) shorthands to the respective Provides 'k' (kubectl), 'h' (helm), and 'f' (flux) shorthands to the respective
utility. These functions leverage redis and scwrypts environments to utility. These functions leverage redis and scwrypts environments to
allow quick selection of contexts and namespaces usable across all allow quick selection of contexts and namespaces usable across all
active shell instances. active shell instances.
@ -100,14 +101,12 @@ _SCWRYPTS_KUBECTL_DRIVER() {
--subsession ) SUBSESSION=$2; shift 1 ;; --subsession ) SUBSESSION=$2; shift 1 ;;
-n | --namespace ) -n | --namespace )
echo "TODO: set namespace ('$2')" >&2 _SCWRYPTS_KUBECTL_DRIVER kubectl meta set namespace $2
USER_ARGS+=(--namespace $2); shift 1 shift 1
;; ;;
-k | --context | --kube-context ) -k | --context | --kube-context )
echo "TODO: set context ('$2')" >&2 _SCWRYPTS_KUBECTL_DRIVER kubectl meta set context $2
[[ $CLI =~ ^helm$ ]] && USER_ARGS+=(--kube-context $2)
[[ $CLI =~ ^kubectl$ ]] && USER_ARGS+=(--context $2)
shift 1 shift 1
;; ;;
@ -149,6 +148,7 @@ _SCWRYPTS_KUBECTL_DRIVER() {
[ $CONTEXT ] && [[ $CLI =~ ^helm$ ]] && CLI_ARGS+=(--kube-context $CONTEXT) [ $CONTEXT ] && [[ $CLI =~ ^helm$ ]] && CLI_ARGS+=(--kube-context $CONTEXT)
[ $CONTEXT ] && [[ $CLI =~ ^kubectl$ ]] && CLI_ARGS+=(--context $CONTEXT) [ $CONTEXT ] && [[ $CLI =~ ^kubectl$ ]] && CLI_ARGS+=(--context $CONTEXT)
[ $CONTEXT ] && [[ $CLI =~ ^flux$ ]] && CLI_ARGS+=(--context $CONTEXT)
[[ $STRICT -eq 1 ]] && { [[ $STRICT -eq 1 ]] && {
[ $CONTEXT ] || ERROR "missing kubectl 'context'" [ $CONTEXT ] || ERROR "missing kubectl 'context'"

View File

@ -30,8 +30,15 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__meta() {
USAGE__args="set (namespace|context)" USAGE__args="set (namespace|context)"
USAGE__description="interactively set a namespace or context for '$SCWRYPTS_ENV'" USAGE__description="interactively set a namespace or context for '$SCWRYPTS_ENV'"
case $2 in case $2 in
namespace | context ) USER_ARGS+=($1 $2) ;; namespace | context ) USER_ARGS+=($1 $2 $3); [ $3 ] && shift 1 ;;
-h | --help ) HELP=1 ;; -h | --help ) HELP=1 ;;
'' )
: \
&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set context \
&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set namespace \
;
return $?
;;
* ) ERROR "cannot set '$2'" ;; * ) ERROR "cannot set '$2'" ;;
esac esac
@ -94,7 +101,7 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta() {
;; ;;
set ) set )
scwrypts -n --name set-$2 --type zsh --group kubectl -- --subsession $SUBSESSION >/dev/null \ scwrypts -n --name set-$2 --type zsh --group kubectl -- $3 --subsession $SUBSESSION >/dev/null \
&& SUCCESS "$2 set" && SUCCESS "$2 set"
;; ;;

View File

@ -21,7 +21,6 @@ KUBECTL() {
kubectl ${KUBECTL_ARGS[@]} $@ kubectl ${KUBECTL_ARGS[@]} $@
} }
##################################################################### #####################################################################
KUBECTL__GET_CONTEXT() { REDIS get --prefix "current:context"; } KUBECTL__GET_CONTEXT() { REDIS get --prefix "current:context"; }
@ -87,3 +86,73 @@ KUBECTL__LIST_NAMESPACES() {
echo default echo default
KUBECTL get namespaces -o name | sed 's/^namespace\///' | sort KUBECTL get namespaces -o name | sed 's/^namespace\///' | sort
} }
#####################################################################
KUBECTL__SERVE() {
[ $CONTEXT ] || local CONTEXT=$(KUBECTL__GET_CONTEXT)
[ $CONTEXT ] || ERROR 'must configure a context in which to serve'
[ $NAMESPACE ] || local NAMESPACE=$(KUBECTL__GET_NAMESPACE)
[ $NAMESPACE ] || ERROR 'must configure a namespace in which to serve'
CHECK_ERRORS --no-fail --no-usage || return 1
[ $SERVICE ] && SERVICE=$(KUBECTL__LIST_SERVICES | jq -c "select (.service == \"$SERVICE\")" || echo $SERVICE)
[ $SERVICE ] || local SERVICE=$(KUBECTL__SELECT_SERVICE)
[ $SERVICE ] || ERROR 'must provide or select a service'
KUBECTL__LIST_SERVICES | grep -q "^$SERVICE$"\
|| ERROR "no service '$SERVICE' in '$CONFIG/$NAMESPACE'"
CHECK_ERRORS --no-fail --no-usage || return 1
##########################################
SERVICE_PASSWORD="$(KUBECTL__GET_SERVICE_PASSWORD)"
KUBECTL__SERVICE_PARSE
INFO "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}"
[ $SERVICE_PASSWORD ] && INFO "password : $SERVICE_PASSWORD"
KUBECTL port-forward service/$SERVICE_NAME $SERVICE_PORT
}
KUBECTL__SELECT_SERVICE() {
[ $NAMESPACE ] || local NAMESPACE=$(KUBECTL__GET_NAMESPACE)
[ $NAMESPACE ] || return 1
local SERVICES=$(KUBECTL__LIST_SERVICES)
local SELECTED=$({
echo "namespace service port"
echo $SERVICES \
| jq -r '.service + " " + .port' \
| sed "s/^/$NAMESPACE /" \
;
} \
| column -t \
| FZF 'select a service' --header-lines=1 \
| awk '{print $2;}' \
)
echo $SERVICES | jq -c "select (.service == \"$SELECTED\")"
}
KUBECTL__LIST_SERVICES() {
KUBECTL get service --no-headers\
| awk '{print "{\"service\":\""$1"\",\"ip\":\""$3"\",\"port\":\""$5"\"}"}' \
| jq -c 'select (.ip != "None")' \
;
}
KUBECTL__GET_SERVICE_PASSWORD() {
[ $PASSWORD_SECRET ] && [ $PASSWORD_KEY ] || return 0
KUBECTL get secret $PASSWORD_SECRET -o jsonpath="{.data.$PASSWORD_KEY}" \
| base64 --decode
}
KUBECTL__SERVICE_PARSE() {
SERVICE_NAME=$(echo $SERVICE | jq -r .service)
SERVICE_PORT=$(echo $SERVICE | jq -r .port | sed 's|/.*$||')
}

58
plugins/kubectl/serve Executable file
View File

@ -0,0 +1,58 @@
#!/bin/zsh
#####################################################################
DEPENDENCIES+=()
REQUIRED_ENV+=()
use kubectl --group kubectl
CHECK_ENVIRONMENT
#####################################################################
MAIN() {
local USAGE="
usage: [service] [...options...]
args:
service (optional) name of the service to forward locally
options:
--context override context
--namespace override namespace
--subsession REDIS subsession (default 0)
to show a required password on screen, use both:
--password-secret Secret resource
--password-key key within Secret's 'data'
-h, --help show this dialogue and exit
"
local CONTEXT NAMESPACE SERVICE
local SUBSESSION=0
while [[ $# -gt 0 ]]
do
case $1 in
--context ) CONTEXT=$2; shift 1 ;;
--namespace ) NAMESPACE=$2; shift 1 ;;
--subsession ) SUBSESSION=$2; shift 1 ;;
--password-secret ) PASSWORD_SECRET=$2; shift 1 ;;
--password-key ) PASSWORD_KEY=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* )
[ $SERVICE ] && ERROR "unexpected argument '$2'"
SERVICE=$1
;;
esac
shift 1
done
CHECK_ERRORS
KUBECTL__SERVE
}
#####################################################################
MAIN $@

View File

@ -17,6 +17,8 @@ MAIN() {
options: options:
--subsession REDIS subsession (default 0) --subsession REDIS subsession (default 0)
-h, --help show this dialogue and exit
" "
local CONTEXT local CONTEXT
local SUBSESSION=0 local SUBSESSION=0
@ -26,6 +28,8 @@ MAIN() {
case $1 in case $1 in
--subsession ) SUBSESSION=$2; shift 1 ;; --subsession ) SUBSESSION=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* ) * )
[ $CONTEXT ] && ERROR "unexpected argument '$2'" [ $CONTEXT ] && ERROR "unexpected argument '$2'"
CONTEXT=$1 CONTEXT=$1

View File

@ -17,6 +17,8 @@ MAIN() {
options: options:
--subsession REDIS subsession (default 0) --subsession REDIS subsession (default 0)
-h, --help show this dialogue and exit
" "
local NAMESPACE local NAMESPACE
local SUBSESSION=0 local SUBSESSION=0
@ -26,6 +28,8 @@ MAIN() {
case $1 in case $1 in
--subsession ) SUBSESSION=$2; shift 1 ;; --subsession ) SUBSESSION=$2; shift 1 ;;
-h | --help ) USAGE; return 0 ;;
* ) * )
[ $NAMESPACE ] && ERROR "unexpected argument '$2'" [ $NAMESPACE ] && ERROR "unexpected argument '$2'"
NAMESPACE=$1 NAMESPACE=$1

9
run
View File

@ -14,6 +14,7 @@ __RUN() {
-m, --name <scwrypt-name> only run the script if there is an exact match -m, --name <scwrypt-name> only run the script if there is an exact match
(requires type and group) (requires type and group)
-y, --yes auto-accept all [yn] prompts through current scwrypt
-e, --env <env-name> set environment; overwrites SCWRYPTS_ENV -e, --env <env-name> set environment; overwrites SCWRYPTS_ENV
-n, --no-log skip logging and run in quiet mode -n, --no-log skip logging and run in quiet mode
@ -56,14 +57,22 @@ __RUN() {
VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/') VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/')
set -- $(echo " $VARSPLIT ") ${@:2} set -- $(echo " $VARSPLIT ") ${@:2}
;; ;;
-h | --help ) -h | --help )
USAGE USAGE
return 0 return 0
;; ;;
-n | --no-log ) -n | --no-log )
[ ! $SUBSCWRYPT ] && SUBSCWRYPT=0 [ ! $SUBSCWRYPT ] && SUBSCWRYPT=0
shift 1 shift 1
;; ;;
-y | --yes )
export __SCWRYPTS_YES=1
shift 1
;;
-e | --env ) -e | --env )
[ ! $2 ] && ERROR "missing value for argument $1" && break [ ! $2 ] && ERROR "missing value for argument $1" && break
[ ! $SUBSCWRYPTS ] \ [ ! $SUBSCWRYPTS ] \

View File

@ -7,4 +7,4 @@ use cloud/aws/eks
CHECK_ENVIRONMENT CHECK_ENVIRONMENT
##################################################################### #####################################################################
EKS_CLUSTER_LOGIN $@ EKS__CLUSTER_LOGIN $@

View File

@ -1,19 +1,44 @@
##################################################################### #####################################################################
DEPENDENCIES+=( DEPENDENCIES+=(kubectl yq)
kubectl REQUIRED_ENV+=()
)
REQUIRED_ENV+=(
AWS_ACCOUNT
AWS_REGION
)
use cloud/aws/cli use cloud/aws/cli
##################################################################### #####################################################################
EKS_CLUSTER_LOGIN() { EKS__KUBECTL() { EKS kubectl $@; }
EKS__FLUX() { EKS flux $@; }
#####################################################################
EKS() {
local USAGE="
usage: cli [...kubectl args...]
args:
cli a kubectl-style CLI (e.g. kubectl, helm, flux, etc)
Allows access to kubernetes CLI commands by configuring environment
to point to a specific cluster.
"
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT CLUSTER_NAME) DEPENDENCIES=(kubectl $1) CHECK_ENVIRONMENT || return 1
local CONTEXT="arn:aws:eks:${AWS_REGION}:${AWS_ACCOUNT}:cluster/${CLUSTER_NAME}"
local CONTEXT_ARGS=()
case $1 in
helm ) CONTEXT_ARGS+=(--kube-context $CONTEXT) ;;
* ) CONTEXT_ARGS+=(--context $CONTEXT) ;;
esac
$1 ${CONTEXT_ARGS[@]} ${@:2}
}
#####################################################################
EKS__CLUSTER_LOGIN() {
local USAGE=" local USAGE="
usage: [...options...] usage: [...options...]
@ -25,6 +50,7 @@ EKS_CLUSTER_LOGIN() {
cluster in EKS. Also creates the kubeconfig entry if it does not cluster in EKS. Also creates the kubeconfig entry if it does not
already exist. already exist.
" "
REQUIRED_ENV=(AWS_ACCOUNT AWS_REGION) CHECK_ENVIRONMENT || return 1
local CLUSTER_NAME local CLUSTER_NAME

View File

@ -0,0 +1,116 @@
#####################################################################
DEPENDENCIES+=(eksctl)
REQUIRED_ENV+=()
use cloud/aws/eks
#####################################################################
EKSCTL() {
REQUIRED_ENV=(AWS_PROFILE AWS_REGION) CHECK_ENVIRONMENT || return 1
AWS_PROFILE=$AWS_PROFILE AWS_REGION=$AWS_REGION \
eksctl $@
}
EKSCTL__CREATE_IAMSERVICEACCOUNT() {
local USAGE="
usage: serviceaccount-name namespace [...options...] -- [...'eksctl create iamserviceaccount' args...]
options:
--serviceaccount (required) target k8s:ServiceAccount
--namespace (required) target k8s:Namespace
--role-name (required) name of the IAM role to assign
--force don't check for existing serviceaccount and override any existing configuration
eksctl create iamserviceaccount args:
$(eksctl create iamserviceaccount --help 2>&1 | grep -v -- '--name' | grep -v -- '--namespace' | grep -v -- '--role-name' | sed 's/^/ /')
"
REQUIRED_ENV=(AWS_REGION AWS_ACCOUNT CLUSTER_NAME) CHECK_ENVIRONMENT || return 1
local SERVICEACCOUNT NAMESPACE ROLE_NAME
local FORCE=0
local EKSCTL_ARGS=()
while [[ $# -gt 0 ]]
do
case $1 in
--serviceaccount ) SERVICEACCOUNT=$2; shift 1 ;;
--namespace ) NAMESPACE=$2; shift 1 ;;
--role-name ) ROLE_NAME=$2; shift 1 ;;
--force ) FORCE=1 ;;
-- ) shift 1; break ;;
* ) ERROR "unknown argument '$1'" ;;
esac
shift 1
done
while [[ $# -gt 0 ]]; do EKSCTL_ARGS+=($1); shift 1; done
[ $SERVICEACCOUNT ] || ERROR "--serviceaccount is required"
[ $NAMESPACE ] || ERROR "--namespace is required"
[ $ROLE_NAME ] || ERROR "--role-name is required"
CHECK_ERRORS --no-fail || return 1
##########################################
[[ $FORCE -eq 0 ]] && {
_EKS__CHECK_IAMSERVICEACCOUNT_EXISTS
local EXISTS_STATUS=$?
case $EXISTS_STATUS in
0 )
SUCCESS "'$NAMESPACE/$SERVICEACCOUNT' already configured with '$ROLE_NAME'"
return 0
;;
1 ) ;; # role does not exist yet; continue with rollout
2 )
ERROR "'$NAMESPACE/$SERVICEACCOUNT' has been configured with a different role than '$ROLE_NAME'"
REMINDER "must use --force flag to overwrite"
return 2
;;
esac
}
STATUS "creating iamserviceaccount" \
&& EKSCTL create iamserviceaccount \
--cluster $CLUSTER_NAME \
--namespace $NAMESPACE \
--name $SERVICEACCOUNT \
--role-name $ROLE_NAME \
--override-existing-serviceaccounts \
--approve \
${EKSCTL_ARGS[@]} \
&& SUCCESS "successfully configured '$NAMESPACE/$SERVICEACCOUNT' with IAM role '$ROLE_NAME'" \
|| { ERROR "unable to configure '$NAMESPACE/$SERVICEACCOUNT' with IAM role '$ROLE_NAME' (check cloudformation dashboard for details)"; return 3; }
}
_EKS__CHECK_IAMSERVICEACCOUNT_EXISTS() {
STATUS "checking for existing role-arn"
local CURRENT_ROLE_ARN=$(
EKS__KUBECTL --namespace $NAMESPACE get serviceaccount $SERVICEACCOUNT -o yaml \
| YQ -r '.metadata.annotations["eks.amazonaws.com/role-arn"]' \
| grep -v '^null$' \
)
[ $CURRENT_ROLE_ARN ] || {
STATUS "serviceaccount does not exist or has no configured role"
return 1
}
[[ $CURRENT_ROLE_ARN =~ "$ROLE_NAME$" ]] || {
STATUS "serviceaccount current role does not match desired role:
CURRENT : $CURRENT_ROLE_ARN
DESIRED : arn:aws:iam::${AWS_ACCOUNT}:role/$ROLE_NAME
"
return 2
}
STATUS "serviceaccount current role matches desired role"
return 0
}

View File

@ -65,6 +65,7 @@ HELM__TEMPLATE__GET() {
[ ! $TEMPLATE_OUTPUT ] && EXIT_CODE=1 [ ! $TEMPLATE_OUTPUT ] && EXIT_CODE=1
[[ $RAW -eq 1 ]] && { [[ $RAW -eq 1 ]] && {
[ $USE_CHART_ROOT ] && [[ $USE_CHART_ROOT -eq 1 ]] || HELM_ARGS+=(--show-only $(echo $TEMPLATE_FILENAME | sed "s|^$CHART_ROOT/||")) [ $USE_CHART_ROOT ] && [[ $USE_CHART_ROOT -eq 1 ]] || HELM_ARGS+=(--show-only $(echo $TEMPLATE_FILENAME | sed "s|^$CHART_ROOT/||"))
[[ $COLORIZE -eq 1 ]] \ [[ $COLORIZE -eq 1 ]] \

View File

@ -27,9 +27,14 @@ HELM__VALIDATE() {
return 1 return 1
} }
CHART_NAME=$(yq -r .name "$CHART_ROOT/Chart.yaml") CHART_NAME=$(YQ -r .name "$CHART_ROOT/Chart.yaml")
[[ $TEMPLATE_FILENAME =~ values*.yaml$ ]] && { [[ $TEMPLATE_FILENAME =~ values.*.yaml$ ]] && {
HELM_ARGS+=(--values $TEMPLATE_FILENAME)
USE_CHART_ROOT=1
}
[[ $TEMPLATE_FILENAME =~ tests/.*.yaml$ ]] && {
HELM_ARGS+=(--values $TEMPLATE_FILENAME) HELM_ARGS+=(--values $TEMPLATE_FILENAME)
USE_CHART_ROOT=1 USE_CHART_ROOT=1
} }
@ -54,9 +59,18 @@ _HELM__GET_CHART_ROOT() {
} }
_HELM__GET_DEFAULT_VALUES_ARGS() { _HELM__GET_DEFAULT_VALUES_ARGS() {
for F in \
"$CHART_ROOT/tests/default.yaml" \
"$CHART_ROOT/values.test.yaml" \
"$CHART_ROOT/values.yaml" \
;
do
[ -f "$F" ] && HELM_ARGS=(--values "$F" $HELM_ARGS)
done
for LOCAL_REPOSITORY in $(\ for LOCAL_REPOSITORY in $(\
cat "$CHART_ROOT/Chart.yaml" \ cat "$CHART_ROOT/Chart.yaml" \
| yq -r '.dependencies[] | .repository' \ | YQ -r '.dependencies[] | .repository' \
| grep '^file://' \ | grep '^file://' \
| sed 's|file://||' \ | sed 's|file://||' \
) )
@ -67,22 +81,13 @@ _HELM__GET_DEFAULT_VALUES_ARGS() {
; ;
for F in \ for F in \
"$LOCAL_REPOSITORY_ROOT/values.yaml" \
"$LOCAL_REPOSITORY_ROOT/values.test.yaml" \
"$LOCAL_REPOSITORY_ROOT/tests/default.yaml" \ "$LOCAL_REPOSITORY_ROOT/tests/default.yaml" \
"$LOCAL_REPOSITORY_ROOT/values.test.yaml" \
"$LOCAL_REPOSITORY_ROOT/values.yaml" \
; ;
do do
[ -f "$F" ] && HELM_ARGS+=(--values "$F") [ -f "$F" ] && HELM_ARGS=(--values "$F" $HELM_ARGS)
done done
done done
for F in \
"$CHART_ROOT/values.yaml" \
"$CHART_ROOT/values.test.yaml" \
"$CHART_ROOT/tests/default.yaml" \
;
do
[ -f "$F" ] && HELM_ARGS+=(--values "$F")
done
} }

View File

@ -17,6 +17,13 @@ __CHECK_DEPENDENCY() {
$E "application '$1' "$([[ $OPTIONAL -eq 1 ]] && echo preferred || echo required)" but not available on PATH $(__CREDITS $1)" $E "application '$1' "$([[ $OPTIONAL -eq 1 ]] && echo preferred || echo required)" but not available on PATH $(__CREDITS $1)"
return 1 return 1
} }
[[ $DEPENDENCY =~ ^yq$ ]] && {
yq --version | grep -q mikefarah \
|| WARNING 'detected kislyuk/yq but mikefarah/yq is preferred (compatibility may vary)'
}
return 0
} }
__CHECK_COREUTILS() { __CHECK_COREUTILS() {
@ -36,7 +43,7 @@ __CHECK_COREUTILS() {
done done
[[ $NON_GNU_DEPENDENCY_COUNT -gt 0 ]] && { [[ $NON_GNU_DEPENDENCY_COUNT -gt 0 ]] && {
WARNING 'scripts rely on GNU coreutils; functionality may be limited' WARNING 'scripts rely on GNU coreutils; compatibility may vary'
IS_MACOS && REMINDER 'GNU coreutils can be installed and linked through Homebrew' IS_MACOS && REMINDER 'GNU coreutils can be installed and linked through Homebrew'
} }

View File

@ -142,6 +142,7 @@ INPUT() {
Yn() { Yn() {
PROMPT "$@ [Yn]" PROMPT "$@ [Yn]"
[ $CI ] && { echo y; return 0; } [ $CI ] && { echo y; return 0; }
[ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; }
local Yn; READ -k Yn; echo >&2 local Yn; READ -k Yn; echo >&2
[[ $Yn =~ [nN] ]] && return 1 || return 0 [[ $Yn =~ [nN] ]] && return 1 || return 0
@ -150,6 +151,7 @@ Yn() {
yN() { yN() {
PROMPT "$@ [yN]" PROMPT "$@ [yN]"
[ $CI ] && { echo y; return 0; } [ $CI ] && { echo y; return 0; }
[ $__SCWRYPTS_YES ] && [[ $__SCWRYPTS_YES -eq 1 ]] && { echo y; return 0; }
local yN; READ -k yN; echo >&2 local yN; READ -k yN; echo >&2
[[ $yN =~ [yY] ]] && return 0 || return 1 [[ $yN =~ [yY] ]] && return 0 || return 1
@ -218,3 +220,12 @@ EDIT() {
$EDITOR $@ </dev/tty >/dev/tty $EDITOR $@ </dev/tty >/dev/tty
SUCCESS "finished editing '$1'!" SUCCESS "finished editing '$1'!"
} }
YQ() {
yq --version | grep -q mikefarah || {
yq $@
return $?
}
yq eval '... comments=""' | yq $@
}