Compare commits
	
		
			3 Commits
		
	
	
		
			v5.0.0
			...
			41da641ab9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 41da641ab9 | |||
| 6ba628f80e | |||
| 1f10268aa0 | 
| @@ -22,14 +22,10 @@ executors: | ||||
|       - image: node:18 | ||||
|     resource_class: medium | ||||
|  | ||||
|   zsh: | ||||
|     docker: | ||||
|       - image: alpine:3 | ||||
|     resource_class: small | ||||
|  | ||||
| commands: | ||||
|   archlinux-run: | ||||
|     description: execute steps in the archlinux container as the CI user | ||||
|     description: execute command steps in the archlinux container from the CI user | ||||
|     parameters: | ||||
|       _name: | ||||
|         type: string | ||||
| @@ -56,13 +52,6 @@ custom: | ||||
|             useradd -m ci | ||||
|             echo "ci ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers | ||||
|  | ||||
|     temp-downgrade-fakeroot: | ||||
|       - &archlinux-temp-downgrade-fakeroot | ||||
|         run: | ||||
|           name: downgrade fakeroot to v1.34 (v1.35 and v1.36 are confirmed to break) | ||||
|           command: | | ||||
|             pacman -U --noconfirm https://archive.archlinux.org/packages/f/fakeroot/fakeroot-1.34-1-x86_64.pkg.tar.zst | ||||
|  | ||||
|     clone-aur: | ||||
|       - &archlinux-clone-aur | ||||
|         archlinux-run: | ||||
| @@ -95,7 +84,6 @@ jobs: | ||||
|     executor: archlinux | ||||
|     steps: | ||||
|       - *archlinux-prepare | ||||
|       - *archlinux-temp-downgrade-fakeroot | ||||
|       - *archlinux-clone-aur | ||||
|       - *archlinux-clone-scwrypts | ||||
|       - archlinux-run: | ||||
| @@ -114,7 +102,6 @@ jobs: | ||||
|             && echo "source=(scwrypts.tar.gz)" >> PKGBUILD | ||||
|             && echo "sha256sums=(SKIP)" >> PKGBUILD | ||||
|             && makepkg --noconfirm -si | ||||
|             && echo validating scwrypts version | ||||
|             && scwrypts --version | grep "^scwrypts v$PKGVER$" | ||||
|             ; | ||||
|  | ||||
| @@ -122,7 +109,6 @@ jobs: | ||||
|     executor: archlinux | ||||
|     steps: | ||||
|       - *archlinux-prepare | ||||
|       - *archlinux-temp-downgrade-fakeroot | ||||
|       - *archlinux-clone-aur | ||||
|       - archlinux-run: | ||||
|           _name: update PKGBUILD and .SRCINFO | ||||
| @@ -247,47 +233,6 @@ jobs: | ||||
|       - run: pip install build && python -m build | ||||
|       - run: pip install twine && twine upload dist/* | ||||
|  | ||||
|   zsh-test: | ||||
|     executor: zsh | ||||
|     working_directory: ~/scwrypts | ||||
|     steps: | ||||
|       - checkout: | ||||
|           path: ~/scwrypts | ||||
|       - run: | ||||
|           name: install dependencies | ||||
|           command: | | ||||
|             : \ | ||||
|               && apk add \ | ||||
|                   coreutils \ | ||||
|                   findutils \ | ||||
|                   fzf \ | ||||
|                   perl \ | ||||
|                   sed \ | ||||
|                   gawk \ | ||||
|                   git \ | ||||
|                   jo \ | ||||
|                   jq \ | ||||
|                   util-linux \ | ||||
|                   uuidgen \ | ||||
|                   yq \ | ||||
|                   zsh \ | ||||
|               ; | ||||
|       - run: | ||||
|           name: scwrypts zsh/unittest | ||||
|           command: | | ||||
|             ~/scwrypts/scwrypts run unittest \ | ||||
|             ; | ||||
|       - run: | ||||
|           name: scwrypts returns proper success codes | ||||
|           command: | | ||||
|             ~/scwrypts/scwrypts -n sanity check -- --exit-code 0 | ||||
|             [[ $? -eq 0 ]] || exit 1 | ||||
|       - run: | ||||
|           shell: /bin/sh | ||||
|           name: scwrypts returns proper error codes | ||||
|           command: | | ||||
|             ~/scwrypts/scwrypts -n sanity check -- --exit-code 101 | ||||
|             [[ $? -eq 101 ]] || exit 1 | ||||
|  | ||||
| workflows: | ||||
|   test: | ||||
| @@ -300,7 +245,6 @@ workflows: | ||||
|  | ||||
|       - python-test: *dev-filters | ||||
|       - nodejs-test: *dev-filters | ||||
|       - zsh-test: *dev-filters | ||||
|  | ||||
|   publish: | ||||
|     jobs: | ||||
| @@ -331,7 +275,6 @@ workflows: | ||||
|             - aur-test | ||||
|             - python-publish | ||||
|             - nodejs-publish | ||||
|             - zsh-test | ||||
|  | ||||
|       - python-test: *only-publish-for-full-semver | ||||
|       - python-publish: | ||||
| @@ -339,7 +282,6 @@ workflows: | ||||
|           context: [pypi-yage] | ||||
|           requires: | ||||
|             - python-test | ||||
|             - zsh-test | ||||
|  | ||||
|       - nodejs-test: *only-publish-for-full-semver | ||||
|       - nodejs-publish: | ||||
| @@ -347,6 +289,3 @@ workflows: | ||||
|           context: [npm-wrynegade] | ||||
|           requires: | ||||
|             - nodejs-test | ||||
|             - zsh-test | ||||
|  | ||||
|       - zsh-test: *only-publish-for-full-semver | ||||
|   | ||||
| @@ -1,89 +0,0 @@ | ||||
| #!/bin/zsh | ||||
| # | ||||
| # a temporary template conversion utility for env.template (<=v4) | ||||
| # to env.yaml (>=v5) | ||||
| # | ||||
| eval $(scwrypts --config) | ||||
| use -c scwrypts/environment-files | ||||
|  | ||||
| ENVIRONMENT_ROOT="$1" | ||||
| [ "$ENVIRONMENT_ROOT" ] || ENVIRONMENT_ROOT="${0:a:h}" | ||||
|  | ||||
| OLDENV="$ENVIRONMENT_ROOT/env.template" | ||||
| NEWENV="$ENVIRONMENT_ROOT/env.yaml" | ||||
| ENVMAP="$ENVIRONMENT_ROOT/.map.txt" | ||||
|  | ||||
| GROUP="$2" | ||||
| [ $GROUP ] || GROUP=scwrypts | ||||
| GENERATE_TEMPLATE \ | ||||
| 	| sed '1,4d; /^$/d' \ | ||||
| 	| sed -z 's/# \([^\n]*\)\n\([^\n]*\)=/\2=\n\2=DESCRIPTION=\1/g' \ | ||||
| 	| sed ' | ||||
| 		s/^export // | ||||
| 		/./i--- | ||||
| 		s/\s\+$// | ||||
| 		s/__/=/g | ||||
| 		s/^\(AWS\|REDIS\)_/\1=/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=$/\L\1:\n  \2:\n    \3:\n      \4:\n        \5:/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=$/\L\1:\n  \2:\n    \3:\n      \4:/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=$/\L\1:\n  \2:\n    \3:/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=$/\L\1:\n  \2:/ | ||||
| 		s/^\([^=]*\)=$/\L\1:/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]\+\)$/\L\1:\n  \2:\n    \3:\n      \4:\n        \5: \E\6/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]\+\)$/\L\1:\n  \2:\n    \3:\n      \4: \E\5/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]*\)=\([^=]\+\)$/\L\1:\n  \2:\n    \3: \E\4/ | ||||
| 		s/^\([^=]*\)=\([^=]*\)=\([^=]\+\)$/\L\1:\n  \2: \E\3/ | ||||
| 		s/^\([^=]*\)=\([^=]\+\)$/\L\1: \E\2/ | ||||
| 		s/: (\(.*\))/: [\1]/ | ||||
| 		/^/,/:/{s/_/-/g} | ||||
| 		' \ | ||||
| 	| sed ' | ||||
| 		s/^    \(description:.*\)/  \1/ | ||||
| 		s/description:/.DESCRIPTION:/ | ||||
| 		' \ | ||||
| 	| sed -z 's/\n\(\s\+\).DESCRIPTION:\([^\n]\+\)/\n\1.DESCRIPTION: >-\n\1  \2/g' \ | ||||
| 	| yq eval-all '. as $item ireduce ({}; . *+ $item)' \ | ||||
| 	> "$NEWENV" \ | ||||
| 	; | ||||
|  | ||||
| cat -- "$OLDENV" \ | ||||
| 	| sed ' | ||||
| 		s/#.*// | ||||
| 		/^$/d | ||||
| 		s/^export // | ||||
| 		s/\s\+$// | ||||
| 		s/^\([^=]*\)=.*/\1=\n\1/ | ||||
| 		' \ | ||||
| 	| sed ' | ||||
| 		/^/s/.*/\L&/ | ||||
| 		/^/s/__/./g | ||||
| 		/^/s/_/-/g | ||||
| 		s/^/./ | ||||
| 		s/\(aws\|redis\)-/\1./ | ||||
| 		' \ | ||||
| 	| perl -pe 's/=\n/^/' \ | ||||
| 	| column -ts '^' \ | ||||
| 	> "$ENVMAP" \ | ||||
| 	; | ||||
|  | ||||
| while read line | ||||
| do | ||||
| 	ENV_VAR=$(echo $line | awk '{print $1;}') | ||||
| 	LOOKUP=$(echo $line | awk '{print $2;}') | ||||
|  | ||||
| 	cp "$NEWENV" "$NEWENV.temp" | ||||
| 	cat "$NEWENV.temp" \ | ||||
| 		| yq ". | $LOOKUP.[\".ENVIRONMENT\"] = \"$ENV_VAR\"" \ | ||||
| 		| yq 'sort_keys(...)' \ | ||||
| 		> "$NEWENV" | ||||
| 		; | ||||
| done < "$ENVMAP" | ||||
|  | ||||
| rm -- "$NEWENV.temp" "$ENVMAP" &>/dev/null | ||||
|  | ||||
| head -n1 -- "$NEWENV" | grep -q "^{}$" && { | ||||
| 	echo '---' > "$NEWENV" | ||||
| } | ||||
|  | ||||
| cat -- "$NEWENV" | yq | ||||
| SUCCESS "new environment saved to '$NEWENV'" | ||||
| @@ -12,9 +12,13 @@ export DISCORD__DEFAULT_AVATAR_URL= | ||||
| export DISCORD__DEFAULT_CHANNEL_ID= | ||||
| export DISCORD__DEFAULT_USERNAME= | ||||
| export DISCORD__DEFAULT_WEBHOOK= | ||||
| export I3__BORDER_PIXEL_SIZE= | ||||
| export I3__DMENU_FONT_SIZE= | ||||
| export I3__GLOBAL_FONT_SIZE= | ||||
| export I3__MODEL_CONFIG= | ||||
| export LINEAR__API_TOKEN= | ||||
| export MEDIA_SYNC__S3_BUCKET= | ||||
| export MEDIA_SYNC__TARGETS= | ||||
| export MEDIA_SYNC__S3_BUCKET | ||||
| export MEDIA_SYNC__TARGETS | ||||
| export REDIS_AUTH= | ||||
| export REDIS_HOST= | ||||
| export REDIS_PORT= | ||||
|   | ||||
| @@ -15,6 +15,11 @@ DISCORD__DEFAULT_CHANNEL_ID | | ||||
| DISCORD__DEFAULT_USERNAME   | | ||||
| DISCORD__DEFAULT_WEBHOOK    | | ||||
|  | ||||
| I3__BORDER_PIXEL_SIZE   | custom i3 configuration settings | ||||
| I3__DMENU_FONT_SIZE     | | ||||
| I3__GLOBAL_FONT_SIZE    | | ||||
| I3__MODEL_CONFIG        | | ||||
|  | ||||
| LINEAR__API_TOKEN  | linear.app project management configuration | ||||
|  | ||||
| MEDIA_SYNC__S3_BUCKET | s3 bucket name and filesystem targets for media backups | ||||
|   | ||||
| @@ -1,66 +0,0 @@ | ||||
| --- | ||||
| aws: | ||||
|   .DESCRIPTION: >- | ||||
|     standard AWS environment variables used by awscli and other tools | ||||
|   account: | ||||
|     .ENVIRONMENT: AWS_ACCOUNT | ||||
|   efs: | ||||
|     local-mount-point: | ||||
|       .DESCRIPTION: >- | ||||
|         fully-qualified path to mount the EFS drive | ||||
|       .ENVIRONMENT: AWS__EFS__LOCAL_MOUNT_POINT | ||||
|   profile: | ||||
|     .ENVIRONMENT: AWS_PROFILE | ||||
|   region: | ||||
|     .ENVIRONMENT: AWS_REGION | ||||
| directus: | ||||
|   .DESCRIPTION: >- | ||||
|     details for a directus instance | ||||
|   api-token: | ||||
|     .ENVIRONMENT: DIRECTUS__API_TOKEN | ||||
|   base-url: | ||||
|     .ENVIRONMENT: DIRECTUS__BASE_URL | ||||
| discord: | ||||
|   .DESCRIPTION: >- | ||||
|     details for discord bot | ||||
|   bot-token: | ||||
|     .ENVIRONMENT: DISCORD__BOT_TOKEN | ||||
|   content-footer: | ||||
|     .ENVIRONMENT: DISCORD__CONTENT_FOOTER | ||||
|   content-header: | ||||
|     .ENVIRONMENT: DISCORD__CONTENT_HEADER | ||||
|   default-avatar-url: | ||||
|     .ENVIRONMENT: DISCORD__DEFAULT_AVATAR_URL | ||||
|   default-channel-id: | ||||
|     .ENVIRONMENT: DISCORD__DEFAULT_CHANNEL_ID | ||||
|   default-username: | ||||
|     .ENVIRONMENT: DISCORD__DEFAULT_USERNAME | ||||
|   default-webhook: | ||||
|     .ENVIRONMENT: DISCORD__DEFAULT_WEBHOOK | ||||
| linear: | ||||
|   .DESCRIPTION: >- | ||||
|     linear.app project management configuration | ||||
|   api-token: | ||||
|     .ENVIRONMENT: LINEAR__API_TOKEN | ||||
| redis: | ||||
|   .DESCRIPTION: >- | ||||
|     redis connection credentials | ||||
|   auth: | ||||
|     .ENVIRONMENT: REDIS_AUTH | ||||
|   host: | ||||
|     .ENVIRONMENT: REDIS_HOST | ||||
|   port: | ||||
|     .ENVIRONMENT: REDIS_PORT | ||||
| twilio: | ||||
|   .DESCRIPTION: >- | ||||
|     twilio account / credentials | ||||
|   account-sid: | ||||
|     .ENVIRONMENT: TWILIO__ACCOUNT_SID | ||||
|   api-key: | ||||
|     .ENVIRONMENT: TWILIO__API_KEY | ||||
|   api-secret: | ||||
|     .ENVIRONMENT: TWILIO__API_SECRET | ||||
|   default-phone-from: | ||||
|     .ENVIRONMENT: TWILIO__DEFAULT_PHONE_FROM | ||||
|   default-phone-to: | ||||
|     .ENVIRONMENT: TWILIO__DEFAULT_PHONE_TO | ||||
							
								
								
									
										85
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,76 +1,59 @@ | ||||
| # *Scwrypts* | ||||
| # *Scwrypts* (Wryn + Scripts) | ||||
|  | ||||
| Scwrypts is a CLI and API for safely running scripts in the terminal, CI, and other automated environments. | ||||
| Scwrypts is a friendly CLI / API for quickly running *sandboxed scripts* in the terminal. | ||||
|  | ||||
| Local runs provide a user-friendly approach to quickly execute CI workflows and automations in your terminal. | ||||
| Each local run runs through an interactive, *sandboxed environment* so you never accidentally run dev credentials in production ever again! | ||||
| In modern developer / dev-ops workflows, scripts require a complex configurations. | ||||
| Without a better solution, the developer is cursed to copy lines-upon-lines of variables into terminals, create random text artifacts, or maybe even commit secure credentials into source. | ||||
| Scwrypts leverages ZSH to give hot-key access to run scripts in such environments. | ||||
|  | ||||
| ## Major Version Upgrade Notice | ||||
|  | ||||
| Please refer to [Version 4 to Version 5 Upgrade Path](./docs/upgrade/v4-to-v5.md) when upgrading from scwrypts v4 to scwrypts v5! | ||||
| Please refer to [Version 3 to Version 4 Upgrade Path](./docs/upgrade/v3-to-v4.md) when upgrading from scwrypts v3 to scwrypts v4! | ||||
|  | ||||
| ## Installation | ||||
| ## Dependencies | ||||
| Due to the wide variety of resources used by scripting libraries, the user is expected to manually resolve dependencies. | ||||
| Dependencies are lazy-loaded, and more information can be found by command error messages or in the appropriate README. | ||||
|  | ||||
| Quick installation is supported through both the [Arch User Repository](https://aur.archlinux.org/packages/scwrypts) and [Homebrew](https://github.com/wrynegade/homebrew-brew/tree/main/Formula) | ||||
| Because Scwrypts relies on Scwrypts (see [Meta Scwrypts](./zsh/scwrypts)), `zsh` must be installed and [`junegunn/fzf`](https://github.com/junegunn/fzf) must be available on your PATH. | ||||
|  | ||||
| ```bash | ||||
| # AUR | ||||
| yay -Syu scwrypts | ||||
| ## Usage | ||||
| Install Scwrypts by cloning this repository and sourcing `scwrypts.plugin.zsh` in your `zshrc`. | ||||
| You can now run Scwrypts using the ZLE hotkey bound to `SCWRYPTS_SHORTCUT` (default `CTRL + W`). | ||||
|  | ||||
| # homebrew | ||||
| brew install wrynegade/scwrypts | ||||
| ```console | ||||
| % cd <path-to-cloned-repo> | ||||
| % echo "source $(pwd)/scwrypts.plugin.zsh >> $HOME/.zshrc" | ||||
| ``` | ||||
|  | ||||
| ### Manual Installation | ||||
| Check out [Meta Scwrypts](./zsh/scwrypts) to quickly set up environments and adjust configuration. | ||||
|  | ||||
| To install scwrypts manually, clone this repository (and take note of where it is installed) | ||||
| Replacing the `/path/to/cloned-repo` appropriately, add the following line to your `~/.zshrc`: | ||||
|  | ||||
| ### No Install / API Usage | ||||
| Alternatively, the `scwrypts` API can be used directly: | ||||
| ```zsh | ||||
| source /path/to/cloned-repo/scwrypts.plugin.zsh | ||||
| ./scwrypts [--env environment-name] (...script-name-patterns...) [-- ...passthrough arguments... ] | ||||
| ``` | ||||
|  | ||||
| The next time you start your terminal, you can now execute scwrypts by using the plugin shortcut(s) (by default `CTRL + SPACE`). | ||||
| Plugin shortcuts are configurable in your scwrypts configuration file found in `~/.config/scwrypts/config.zsh`, and [here is the default config](./zsh/config.user.zsh). | ||||
| Given one or more script patterns, Scwrypts will filter the commands by pattern conjunction. | ||||
| If only one command is found which matches the pattern(s), it will immediately begin execution. | ||||
| If multiple commands match, the user will be prompted to select from the filtered list. | ||||
| Of course, if no commands match, Scwrypts will exit with an error. | ||||
|  | ||||
| If you want to use the `scwrypts` program directly, you can either invoke the executable `./scwrypts` or link it in your PATH for easy access. | ||||
| For example, if you have `~/.local/bin` in your PATH, you might run: | ||||
| ```zsh | ||||
| ln -s /path/to/cloned-repo/scwrypts "${HOME}/.local/bin/scwrypts" | ||||
| ``` | ||||
| Given no script patterns, Scwrypts becomes an interactive CLI, prompting the user to select a command. | ||||
|  | ||||
| #### PATH Dependencies | ||||
|  | ||||
| Scwrypts provides a framework for workflows which often depend on a variety of other tools. | ||||
| Although the lazy-loaded dependency model allows hardening in CI and extendability, the user is expected to _resolve required PATH dependencies_. | ||||
|  | ||||
| When running locally, this is typically as simple as "install the missing program," but this may require additional steps when working in automated environments. | ||||
|  | ||||
| By default, the `ci` plugin is enabled which provides the `check all dependencies` scwrypt. | ||||
| You can run this to output a comprehensive list of PATH dependencies across all scwrypts groups, but, at a bare minimum, you will need the following applications in your PATH: | ||||
|  | ||||
| ```bash | ||||
| zsh | ||||
|  | ||||
| grep  # GNU | ||||
| sed   # GNU | ||||
| sort  # GNU | ||||
|  | ||||
| fzf   # https://github.com/junegunn/fzf (only required for interactive / local) | ||||
| jo    # https://github.com/jpmens/jo | ||||
| jq    # https://github.com/jqlang/jq | ||||
| yq    # https://github.com/mikefarah/yq | ||||
| ``` | ||||
| After determining which script to run, if no environment has been specified, Scwrypts prompts the user to choose one. | ||||
|  | ||||
|  | ||||
| ## Usage in CI and Automated Environments | ||||
|  | ||||
| Set environment variable `CI=true` to run scwrypts in an automated environment. | ||||
| ### Using in CI/CD or Automated Workflows | ||||
| Set environment variable `CI=true` (and use the no install method) to run in an automated pipeline. | ||||
| There are a few notable changes to this runtime: | ||||
| - **The Scwrypts sandbox environment will not load.** All variables will be read directly from the current context. | ||||
| - **The Scwrypts sandbox environment will not load.** All variables will be read from context. | ||||
| - User yes/no prompts will **always be YES** | ||||
| - Other user input will default to an empty string | ||||
| - Logs will not be captured in the user's local cache | ||||
| - In GitHub actions, `*.scwrypts.zsh` groups are detected automatically from the `$GITHUB_WORKSPACE`; set `SCWRYPTS_GITHUB_NO_AUTOLOAD=true` to disable | ||||
| - Logs will not be captured | ||||
| - Setting the environment variable `SCWRYPTS_GROUP_LOADER__[a-z_]\+` will source the file indicated in the variable (this allows custom groups without needing to modify the `config.zsh` directly) | ||||
| 	- In GitHub actions, `*.scwrypts.zsh` groups are detected automatically from the `$GITHUB_WORKSPACE`; set `SCWRYPTS_GITHUB_NO_AUTOLOAD=true` to disable | ||||
|  | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
|             ___________________________ | ||||
|             ___________________________  | ||||
|            < ~thanks for your support~ > | ||||
|             --------------------------- | ||||
|             ---------------------------  | ||||
|                    \   ^__^ | ||||
|                     \  (oo)\_______ | ||||
|                        (__)\       )\/\ | ||||
|   | ||||
| @@ -57,7 +57,7 @@ Don't worry, it's easy. | ||||
| Take your original scwrypt, and slap the executable stuff into a function called `MAIN` (yes, it must be _exactly_, all-caps `MAIN`): | ||||
|  | ||||
| ```diff | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| ##################################################################### | ||||
| DEPENDENCIES+=(dep-function-a dep-function-b) | ||||
| REQUIRED_ENV+=() | ||||
| @@ -69,11 +69,11 @@ CHECK_ENVIRONMENT | ||||
|  | ||||
| - echo "do some stuff here" | ||||
| - # ... etc ... | ||||
| - echo.success "completed the stuff" | ||||
| - SUCCESS "completed the stuff" | ||||
| + MAIN() { | ||||
| +     echo "do some stuff here" | ||||
| +     # ... etc ... | ||||
| +     echo.success "completed the stuff | ||||
| +     SUCCESS "completed the stuff | ||||
| + } | ||||
| ``` | ||||
|  | ||||
| @@ -85,7 +85,7 @@ All I had to do in this case was delete the function invocation at the end: | ||||
| ```diff | ||||
| # ... top boilerplate ... | ||||
| MAIN() { | ||||
|     echo.success "look at me I'm so cool I already wrote this in a main function" | ||||
|     SUCCESS "look at me I'm so cool I already wrote this in a main function" | ||||
| } | ||||
| - | ||||
| - ##################################################################### | ||||
| @@ -115,20 +115,20 @@ Also you can ditch the `CHECK_ENVIRONMENT`. | ||||
| While it won't hurt, v4 already does this, so just get rid of it. | ||||
| Here's my recommended formatting: | ||||
| ```diff | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| - ##################################################################### | ||||
| DEPENDENCIES+=(dep-function-a dep-function-b) | ||||
| - REQUIRED_ENV+=() | ||||
|  | ||||
| use do/awesome/stuff --group my-custom-library | ||||
| - | ||||
| -  | ||||
| - CHECK_ENVIRONMENT | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
|     echo "do some stuff here" | ||||
|     # ... etc ... | ||||
|     echo.success "completed the stuff | ||||
|     SUCCESS "completed the stuff | ||||
| } | ||||
| ``` | ||||
|  | ||||
| @@ -164,7 +164,7 @@ If you _have_ done it already, typically by writing a variable called "USAGE" in | ||||
|  | ||||
| Returning to our original `MAIN()` example, I'll add some options parsing so we should now look something like this: | ||||
| ```sh | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(dep-function-a dep-function-b) | ||||
|  | ||||
| use do/awesome/stuff --group my-custom-library | ||||
| @@ -200,7 +200,7 @@ I want to call out a few specific ones: | ||||
|  | ||||
| Just add another section to define these values before declaring `MAIN`: | ||||
| ```sh | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(dep-function-a dep-function-b) | ||||
|  | ||||
| use do/awesome/stuff --group my-custom-library | ||||
|   | ||||
| @@ -1,136 +0,0 @@ | ||||
| # Scwrypts Upgrade v4 to v5 Notes | ||||
|  | ||||
| Although scwrypts v4 brings a number of new features, most functionality is backwards-compatible. | ||||
|  | ||||
| ## Lots of renames! | ||||
|  | ||||
| Nearly every module received a rename. | ||||
| This was a decision made to improve both style-consistency and import transparency, but has resulted in a substantial number of breaking changes to `zsh-type scwrypts modules`. | ||||
|  | ||||
| ### `zsh/utils` Functions | ||||
|  | ||||
| The functions in the underlying library have all been renamed, but otherwise maintain the same functionality. | ||||
| For a full reference, check out the [zsh/utils](../../zsh/utils/utils.module.zsh), but some critical renames are: | ||||
| ```bash | ||||
| FZF            >> utils.fzf | ||||
| FZF_USER_INPUT >> utils.fzf.user-input | ||||
| LESS           >> utils.less | ||||
| YQ             >> utils.yq | ||||
|  | ||||
| SUCCESS  >> echo.success | ||||
| ERROR    >> echo.error | ||||
| REMINDER >> echo.reminder | ||||
| STATUS   >> echo.status | ||||
| WARNING  >> echo.warning | ||||
| DEBUG    >> echo.debug | ||||
| FAIL     >> utils.fail | ||||
| ABORT    >> utils.abort | ||||
|  | ||||
| CHECK_ERRORS >> utils.check-errors | ||||
|  | ||||
| Yn >> utils.Yn | ||||
| yN >> utils.yN | ||||
|  | ||||
| EDIT >> utils.io.edit | ||||
|  | ||||
| CHECK_ENVIRONMENT >> utils.check-environment | ||||
| ``` | ||||
|  | ||||
| ### `zsh/utils` Color Functions | ||||
|  | ||||
| Rather than storing ANSI colors as a variable, colors are now stored as a function which prints the color code. | ||||
| Doing this has proven more versatile than trying to extract the value of the variable in several contexts. | ||||
| Rename looks like this for all named ANSI colors: | ||||
|  | ||||
| ```bash | ||||
| $__GREEN      >> utils.colors.green | ||||
| $__BRIGHT_RED >> utils.colors.bright-red | ||||
| ``` | ||||
|  | ||||
| The most common use case of colors is indirectly through the `echo.*` commands, so a new function now provides _the color used by the associated `echo.*` command_: | ||||
|  | ||||
| ```bash | ||||
| # instead of | ||||
| STATUS "Hello there, ${_BRIGHT_GREEN}bobby${_YELLOW}. How are you?" | ||||
|  | ||||
| # use | ||||
| echo.status "Hello there, $(utils.colors.bright-green)bobby$(echo.status.color). How are you? | ||||
| ``` | ||||
|  | ||||
| ### ZSH Scwrypts Module Naming | ||||
|  | ||||
| **This is the biggest point of refactor.** | ||||
|  | ||||
| You will notice that modules now declare their functions using a `${scwryptsmodule}` notation. | ||||
| This notation provides a dot-notated name which is intended to provide a consistent, unique naming system in ZSH (remember, everything loaded into the same shell script must have a globally-unique name). | ||||
| Consider the new naming method for the following: | ||||
|  | ||||
| ```bash | ||||
| # v4: zsh/lib/helm/template.module.zsh | ||||
|  | ||||
| HELM__TEMPLATE__GET() { | ||||
|     # ... | ||||
| } | ||||
|  | ||||
| # v5: zsh/helm/get-template.module.zsh | ||||
| ${scwryptsmodule}() { | ||||
|     # ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Although the import syntax is generally the same, now we reference the full name of the module instead of the arbitrarily defined `HELM__TEMPLATE__GET`: | ||||
|  | ||||
| ``` | ||||
| # in some other scwrypt | ||||
| use helm/get-template | ||||
|  | ||||
| helm.get-template --raw ./my-helm-chart | ||||
| ``` | ||||
|  | ||||
| The name `${scwryptsmodule}` is depended on the scwrypts library path. | ||||
| Since there is not an easy way to provide an exhaustive list, go through all the places where you `use` something from the scwrypts core library, and check to see where it is now. | ||||
| One of the critical call-outs is the AWS CLI, which no longer follows the "just use ALL CAPS for function names," but instead is a proper module. | ||||
|  | ||||
| Both of the following are valid ways to use the scwrypts-safe aws-cli (`AWS` in v4): | ||||
|  | ||||
| ```bash | ||||
| # to import _only_ AWS cli | ||||
| use cloud.aws.cli | ||||
|  | ||||
| cloud.aws.cli sts get-caller-identity | ||||
|  | ||||
| # importing the full AWS module also provides an alias | ||||
| use cloud.aws | ||||
|  | ||||
| cloud.aws sts get-caller-identity | ||||
| ``` | ||||
|  | ||||
| ### Great news! | ||||
|  | ||||
| Great news! | ||||
| We have finished with **all of the necessary steps** to migrate to v5! | ||||
|  | ||||
| If you still have the energy, take some time to make these _recommended_ adjustments too. | ||||
|  | ||||
|  | ||||
| ### Use the new `${scwryptsmodule}` syntax | ||||
|  | ||||
| The `${scwryptsmodule}` name is now automatically available in any module. | ||||
| The one change from the `${scwryptsmodule}` in scwrypts core is that **your scwrypts group name is the first dot**. | ||||
|  | ||||
| If I'm building the scwrypts group called `my-cool-stuff` and open the file `my-cool-stuff/zsh/module-a.module.zsh`, then `${scwryptsmodule}` will refer to `my-cool-stuff.module-a`. | ||||
|  | ||||
| ### Update your `*.scwrypts.zsh` declaration file | ||||
|  | ||||
| In v4 and earlier, it was tricky to create your own scwrypts group, since you had to create a particular folder structure, and write a `group-name.scwrypts.zsh` file with some somewhat arbitrary requirements. | ||||
| In v5, you can now make any folder a scwrypts group by simply _creating the `*.scwrypts.zsh` file_. | ||||
|  | ||||
| ```bash | ||||
| # this will turn the current folder into the root of a scwrypts group called `my-cool-stuff` | ||||
| touch 'my-cool-stuff.scwrypts.zsh' | ||||
|     ├── zsh | ||||
|     ├── zx | ||||
|     └── py | ||||
| ``` | ||||
|  | ||||
| Advanced options for scwrypts are now [documented in the example](../../scwrypts.scwrypts.zsh), so please refer to it for any additional changes you may need for existing scwrypts modules. | ||||
| @@ -1 +0,0 @@ | ||||
| --- | ||||
| @@ -1,3 +1,10 @@ | ||||
| # CI Helper | ||||
| # Kubernetes `kubectl` Helper Plugin | ||||
|  | ||||
| Disabled by default, this is used in CI contexts to try and identify missing requirements for the current workflow. | ||||
| Leverages a local `redis` application to quickly and easily set an alias `k` for `kubectl --context <some-context> --namespace <some-namespace>`. | ||||
| Much like scwrypts environments, `k` aliases are *only* shared amongst session with the same `SCWRYPTS_ENV` to prevent accidental cross-contamination. | ||||
|  | ||||
|  | ||||
| ## Getting Started | ||||
|  | ||||
| Enable the plugin in `~/.config/scwrypts/config.zsh` by adding `SCWRYPTS_PLUGIN_ENABLED__KUBECTL=1`. | ||||
| Use `k` as your new `kubectl` and checkout `k --help` and `k meta --help`. | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| ##################################################################### | ||||
| MAIN() { | ||||
| 	cd "$(scwrypts.config.group scwrypts root)" | ||||
| 	cd "$SCWRYPTS_ROOT__scwrypts/" | ||||
|  | ||||
| 	DEPENDENCIES+=() | ||||
| 	for group in ${SCWRYPTS_GROUPS[@]} | ||||
| @@ -11,7 +11,7 @@ MAIN() { | ||||
| 		GROUP_HOME="$(eval 'echo $SCWRYPTS_ROOT__'$group)" | ||||
| 		[ $GROUP_HOME ] && [ -d "$GROUP_HOME" ] || continue | ||||
|  | ||||
| 		echo.status "checking dependencies for $group" | ||||
| 		STATUS "checking dependencies for $group" | ||||
| 		DEPENDENCIES+=($( | ||||
| 			for file in $( | ||||
| 				{ | ||||
| @@ -21,13 +21,13 @@ MAIN() { | ||||
| 				} | grep -v '\.md$' | grep -v 'check-all-dependencies$') | ||||
| 			do | ||||
| 				sed -z 's/.*DEPENDENCIES+=(\([^)]*\)).*/\1\n/; s/#.*\n//g; s/\s\+/\n/g' "$GROUP_HOME/$file" | ||||
| 			done | ||||
| 			done  | ||||
| 		)) | ||||
| 	done | ||||
|  | ||||
| 	DEPENDENCIES=(zsh $(echo $DEPENDENCIES | sed 's/ /\n/g' | sort -u | grep '^[-_a-zA-Z]\+$')) | ||||
|  | ||||
| 	echo.status "discovered dependencies: ($DEPENDENCIES)" | ||||
| 	STATUS "discovered dependencies: ($DEPENDENCIES)" | ||||
| 	echo $DEPENDENCIES | sed 's/ /\n/g' | ||||
| 	utils.check-environment && echo.success "all dependencies satisfied" | ||||
| 	CHECK_ENVIRONMENT && SUCCESS "all dependencies satisfied" | ||||
| } | ||||
|   | ||||
| @@ -1 +1,5 @@ | ||||
| export ${scwryptsgroup}__type=zsh | ||||
| SCWRYPTS_GROUPS+=(ci) | ||||
| 
 | ||||
| export SCWRYPTS_TYPE__ci=zsh | ||||
| export SCWRYPTS_ROOT__ci="$SCWRYPTS_ROOT__scwrypts/plugins/ci" | ||||
| export SCWRYPTS_COLOR__ci='\033[0m' | ||||
|   | ||||
| @@ -1,5 +0,0 @@ | ||||
| --- | ||||
| scwrypts-kubectl-redis: | ||||
|   .DESCRIPTION: >- | ||||
|     [currently only 'managed'] 'managed' or 'custom' redis configuration | ||||
|   .ENVIRONMENT: SCWRYPTS_KUBECTL_REDIS | ||||
| @@ -1,10 +0,0 @@ | ||||
| export ${scwryptsgroup}__type=zsh | ||||
| export ${scwryptsgroup}__color=$(utils.colors.red) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| SCWRYPTS_STATIC_CONFIG__kubectl+=( | ||||
| 	"${scwryptsgrouproot}/.config/static/redis.zsh" | ||||
| ) | ||||
| 
 | ||||
| source "${scwryptsgrouproot}/driver/kubectl.driver.zsh" | ||||
| @@ -1,18 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| DEPENDENCIES+=(kubectl) | ||||
| 
 | ||||
| use redis --group kube | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| kube.cli() { | ||||
| 	local NAMESPACE="$(kube.redis get --prefix "current:namespace")" | ||||
| 	local CONTEXT="$(kube.kubectl.context.get)" | ||||
| 
 | ||||
| 	local ARGS=() | ||||
| 	[ "${NAMESPACE}" ] && ARGS+=(--namespace "${NAMESPACE}") | ||||
| 	[ "${CONTEXT}"   ] && ARGS+=(--context "${CONTEXT}") | ||||
| 
 | ||||
| 	kubectl ${ARGS[@]} $@ | ||||
| } | ||||
| @@ -1,56 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use --group kube kubectl/cli | ||||
| use --group kube kubectl/namespace | ||||
| use --group kube redis | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.get() { kube.redis get --prefix "current:context"; } | ||||
| 
 | ||||
| ${scwryptsmodule}.set() { | ||||
| 	local CONTEXT=$1 | ||||
| 	[ ! "${CONTEXT}" ] && return 1 | ||||
| 
 | ||||
| 	[[ "${CONTEXT}" =~ reset ]] && { | ||||
| 		: \ | ||||
| 			&& kube.redis del --prefix "current:context" \ | ||||
| 			&& kube.kubectl.namespace.set reset \ | ||||
| 			; | ||||
| 		return $? | ||||
| 	} | ||||
| 
 | ||||
| 	: \ | ||||
| 		&& kube.redis set --prefix "current:context" "${CONTEXT}" \ | ||||
| 		&& kube.kubectl.namespace.set reset \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.select() { | ||||
| 	case "$(kube.kubectl.context.list | grep -v '^reset$' | wc -l)" in | ||||
| 		( 0 ) | ||||
| 			echo.error "no contexts available" | ||||
| 			return 1 | ||||
| 			;; | ||||
| 		( 1 ) | ||||
| 			kube.kubectl.context.list | tail -n1 | ||||
| 			;; | ||||
| 		( * ) | ||||
| 			kube.kubectl.context.list | utils.fzf 'select a context' | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.list() { | ||||
| 	echo reset | ||||
| 	local ALL_CONTEXTS="$(kube.cli config get-contexts -o name | sort -u)" | ||||
| 
 | ||||
| 	echo "${ALL_CONTEXTS}" | grep -v '^arn:aws:eks' | ||||
| 
 | ||||
| 	[[ "${AWS_ACCOUNT}" ]] && { | ||||
| 		echo "${ALL_CONTEXTS}" | grep "^arn:aws:eks:.*:${AWS_ACCOUNT}" | ||||
| 		true | ||||
| 	} || { | ||||
| 		echo "${ALL_CONTEXTS}" | grep '^arn:aws:eks' | ||||
| 	} | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| # | ||||
| # combines kubectl with redis to both facilitate use of kubectl | ||||
| # between varying contexts/namespaces AND grant persistence between | ||||
| # terminal sessions | ||||
| # | ||||
| 
 | ||||
| # redis wrapper for kubectl | ||||
| use --group kube kubectl/cli | ||||
| 
 | ||||
| # simplify commands for kubecontexts | ||||
| use --group kube kubectl/context | ||||
| 
 | ||||
| # simplify commands for namespaces | ||||
| use --group kube kubectl/namespace | ||||
| 
 | ||||
| # local redirect commands for remote kubernetes services | ||||
| use --group kube kubectl/service | ||||
| @@ -1,23 +0,0 @@ | ||||
| ${scwryptsmodule}.get() { kube.redis get --prefix "current:namespace"; } | ||||
| 
 | ||||
| ${scwryptsmodule}.set() { | ||||
| 	local NAMESPACE=$1 | ||||
| 	[ ! "${NAMESPACE}" ] && return 1 | ||||
| 
 | ||||
| 	[[ "${NAMESPACE}" =~ reset ]] && { | ||||
| 		kube.redis del --prefix "current:namespace" | ||||
| 		return $? | ||||
| 	} | ||||
| 
 | ||||
| 	kube.redis set --prefix "current:namespace" "${NAMESPACE}" | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.select() { | ||||
| 	kube.kubectl.namespace.list | utils.fzf 'select a namespace' | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.list() { | ||||
| 	echo reset | ||||
| 	echo default | ||||
| 	kube.cli get namespaces -o name | sed 's/^namespace\///' | sort | grep -v '^default$' | ||||
| } | ||||
| @@ -1,77 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use --group kube kubectl/cli | ||||
| use --group kube kubectl/context | ||||
| use --group kube kubectl/namespace | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.serve() { | ||||
| 	[ "${CONTEXT}" ] || local CONTEXT="$(kube.kubectl.context.get)" | ||||
| 	[ "${CONTEXT}" ] || echo.error 'must configure a context in which to serve' | ||||
| 
 | ||||
| 	[ "${NAMESPACE}" ] || local NAMESPACE="$(kube.kubectl.namespace.get)" | ||||
| 	[ "${NAMESPACE}" ] || echo.error 'must configure a namespace in which to serve' | ||||
| 
 | ||||
| 	utils.check-errors --no-usage || return 1 | ||||
| 
 | ||||
| 	[ "${SERVICE}" ] && SERVICE="$(kube.kubectl.service.list | jq -c "select (.service == \"${SERVICE}\")" || echo ${SERVICE})" | ||||
| 	[ "${SERVICE}" ] || local SERVICE="$(kube.kubectl.service.select)" | ||||
| 	[ "${SERVICE}" ] || echo.error 'must provide or select a service' | ||||
| 
 | ||||
| 	kube.kubectl.service.list | grep -q "^${SERVICE}$"\ | ||||
| 		|| echo.error "no service '${SERVICE}' in '${CONFIG}/${NAMESPACE}'" | ||||
| 
 | ||||
| 	utils.check-errors --no-usage || return 1 | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	SERVICE_PASSWORD="$(kube.kubectl.service.get-password)" | ||||
| 	kube.kubectl.service.parse | ||||
| 
 | ||||
| 	echo.reminder "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}" | ||||
| 	[ "${SERVICE_PASSWORD}" ] && echo.reminder "password : ${SERVICE_PASSWORD}" | ||||
| 
 | ||||
| 	kube.cli port-forward "service/${SERVICE_NAME}" "${SERVICE_PORT}" | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.select() { | ||||
| 	[ "${NAMESPACE}" ] || local NAMESPACE="$(kube.kubectl.namespace.get)" | ||||
| 	[ "${NAMESPACE}" ] || return 1 | ||||
| 
 | ||||
| 	local SERVICES="$(kube.kubectl.service.list)" | ||||
| 	local SELECTED="$({ | ||||
| 		echo "namespace service port" | ||||
| 		echo ${SERVICES} \ | ||||
| 			| jq -r '.service + " " + .port' \ | ||||
| 			| sed "s/^/${NAMESPACE} /" \ | ||||
| 			; | ||||
| 	} \ | ||||
| 		| column -t \ | ||||
| 		| utils.fzf 'select a service' --header-lines=1 \ | ||||
| 		| awk '{print $2;}' \ | ||||
| 	)" | ||||
| 
 | ||||
| 	echo "${SERVICES}" | jq -c "select (.service == \"${SELECTED}\")" | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.list() { | ||||
| 	kube.cli get service --no-headers\ | ||||
| 		| awk '{print "{\"service\":\""$1"\",\"ip\":\""$3"\",\"port\":\""$5"\"}"}' \ | ||||
| 		| jq -c 'select (.ip != "None")' \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.get-password() { | ||||
| 	[ "${PASSWORD_SECRET}" ] && [ "${PASSWORD_KEY}" ] || return 0 | ||||
| 
 | ||||
| 	kube.cli get secret "${PASSWORD_SECRET}" -o jsonpath="{.data.${PASSWORD_KEY}}" \ | ||||
| 		| base64 --decode | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { | ||||
| 	SERVICE_NAME="$(echo "${SERVICE}" | jq -r .service)" | ||||
| 	SERVICE_PORT="$(echo "${SERVICE}" | jq -r .port | sed 's|/.*$||')" | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use redis --group kube | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	echo $(kube.redis --get-static-definition) | ||||
| } | ||||
| @@ -6,11 +6,10 @@ for CLI in kubectl helm flux | ||||
| do | ||||
| 	eval "_${CLI[1]}() { | ||||
| 		local SUBSESSION=0 | ||||
| 		local SUBSESSION_OFFSET=2 | ||||
| 		echo \${words[2]} | grep -q '^[0-9]\\+$' && SUBSESSION=\${words[2]} && SUBSESSION_OFFSET=3 | ||||
| 		echo \${words[2]} | grep -q '^[0-9]\\+$' && SUBSESSION=\${words[2]} | ||||
| 
 | ||||
| 		local PASSTHROUGH_WORDS=($CLI) | ||||
| 		[[ \$CURRENT -gt \${SUBSESSION_OFFSET} ]] && echo \${words[\${SUBSESSION_OFFSET}]} | grep -qv '^[0-9]\\+$' && { | ||||
| 		[[ \$CURRENT -gt 2 ]] && echo \${words[2]} | grep -qv '^[0-9]\\+$' && { | ||||
| 			local KUBECONTEXT=\$(k \$SUBSESSION meta get context) | ||||
| 			local NAMESPACE=\$(k \$SUBSESSION meta get namespace) | ||||
| 
 | ||||
| @@ -27,8 +26,8 @@ do | ||||
| 		for WORD in \${words[@]:1} | ||||
| 		do | ||||
| 			case \$WORD in | ||||
| 				( [0-9]* ) continue ;; | ||||
| 				( -- ) | ||||
| 				[0-9]* ) continue ;; | ||||
| 				-- ) | ||||
| 					echo \$words | grep -q 'exec' && ((DELIMIT_COUNT+=1)) | ||||
| 					[[ \$DELIMIT_COUNT -eq 0 ]] && ((DELIMIT_COUNT+=1)) && continue | ||||
| 					;; | ||||
| @@ -38,7 +37,7 @@ do | ||||
| 
 | ||||
| 		echo \"\$words\" | grep -q '\\s\\+$' && PASSTHROUGH_WORDS+=(' ') | ||||
| 
 | ||||
| 		words=\"\${PASSTHROUGH_WORDS[@]}\" | ||||
| 		words=\"\$PASSTHROUGH_WORDS\" | ||||
| 		_$CLI | ||||
| 	} | ||||
| 	" | ||||
| @@ -1,18 +1,19 @@ | ||||
| [[ $SCWRYPTS_KUBECTL_DRIVER_READY -eq 1 ]] && return 0 | ||||
| 
 | ||||
| unalias k h f >/dev/null 2>&1 | ||||
| unalias k h >/dev/null 2>&1 | ||||
| k() { _SCWRYPTS_KUBECTL_DRIVER kubectl $@; } | ||||
| h() { _SCWRYPTS_KUBECTL_DRIVER helm $@; } | ||||
| f() { _SCWRYPTS_KUBECTL_DRIVER flux $@; } | ||||
| 
 | ||||
| 
 | ||||
| _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 	[ ! $SCWRYPTS_ENV ] && { | ||||
| 		echo.error "must set SCWRYPTS_ENV in order to use '$(echo $CLI | head -c1)'" | ||||
| 		ERROR "must set SCWRYPTS_ENV in order to use '$(echo $CLI | head -c1)'" | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	which kube.redis >/dev/null 2>&1 \ | ||||
| 		|| eval "$(scwrypts -n --name meta/get-static-redis-definition --type zsh --group kube)" | ||||
| 	which REDIS >/dev/null 2>&1 \ | ||||
| 		|| eval "$(scwrypts -n --name meta/get-static-redis-definition --type zsh --group kubectl)" | ||||
| 
 | ||||
| 	local CLI="$1"; shift 1 | ||||
| 
 | ||||
| @@ -38,16 +39,16 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 		description: - | ||||
| 	" | ||||
| 
 | ||||
| 	local USAGE__usage=$(echo $CLI | head -c1) | ||||
| 	local USAGE__usage=$(echo $CLI | head -c1)  | ||||
| 
 | ||||
| 	local USAGE__args="$( | ||||
| 		{ | ||||
| 			echo "$(utils.colors.print green '[0-9]')^if the first argument is a number 0-9, uses or creates a subsession (default 0)" | ||||
| 			echo "\\033[0;32m[0-9]\\033[0m^if the first argument is a number 0-9, uses or creates a subsession (default 0)" | ||||
| 			echo " ^ " | ||||
| 			for C in ${CUSTOM_COMMANDS[@]} | ||||
| 			do | ||||
| 				echo "$(utils.colors.print green ${C})^$(SCWRYPTS_KUBECTL_CUSTOM_COMMAND_DESCRIPTION__$C 2>/dev/null)" | ||||
| 			done | ||||
| 				echo "\\033[0;32m$C\\033[0m^$(SCWRYPTS_KUBECTL_CUSTOM_COMMAND_DESCRIPTION__$C 2>/dev/null)" | ||||
| 			done  | ||||
| 		} | column -ts '^' | ||||
| 	)" | ||||
| 
 | ||||
| @@ -61,18 +62,18 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 		utility. These functions leverage redis and scwrypts environments to | ||||
| 		allow quick selection of contexts and namespaces usable across all | ||||
| 		active shell instances. | ||||
| 
 | ||||
| 		 | ||||
| 		The scwrypts group 'kubectl' has simple selection executables for | ||||
| 		kubecontext and namespace, but also provides the library to enable | ||||
| 		enriched, use-case-sensitive setup of kubernetes context. | ||||
| 
 | ||||
| 		All actions are scoped to the current SCWRYPTS_ENV | ||||
| 		  currently : $(utils.colors.print yellow ${SCWRYPTS_ENV}) | ||||
| 
 | ||||
| 		  currently : \\033[0;33m$SCWRYPTS_ENV\\033[0m | ||||
| 		   | ||||
| 		" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	 | ||||
| 	local USER_ARGS=() | ||||
| 
 | ||||
| 	local CUSTOM_COMMAND=0 | ||||
| @@ -134,9 +135,9 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 	while [[ $# -gt 0 ]]; do USER_ARGS+=($1); shift 1; done | ||||
| 
 | ||||
| 
 | ||||
| 	utils.check-errors || return 1 | ||||
| 	CHECK_ERRORS --no-fail || return 1 | ||||
| 
 | ||||
| 	[[ $HELP -eq 1 ]] && { utils.io.usage; return 0; } | ||||
| 	[[ $HELP -eq 1 ]] && { USAGE; return 0; } | ||||
| 
 | ||||
| 	##################################################################### | ||||
| 
 | ||||
| @@ -154,12 +155,12 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 			[ $CONTEXT ] && [[ $CLI =~ ^flux$    ]] && CLI_ARGS+=(--context $CONTEXT) | ||||
| 
 | ||||
| 			[[ $STRICT -eq 1 ]] && { | ||||
| 				[ $CONTEXT   ] || echo.error "missing kubectl 'context'" | ||||
| 				[ $NAMESPACE ] || echo.error "missing kubectl 'namespace'" | ||||
| 				[ $CONTEXT   ] || ERROR "missing kubectl 'context'" | ||||
| 				[ $NAMESPACE ] || ERROR "missing kubectl 'namespace'" | ||||
| 
 | ||||
| 				utils.check-errors --no-fail --no-usage || { | ||||
| 					echo.error "with 'strict' settings enabled, context and namespace must be set!" | ||||
| 					echo.reminder " | ||||
| 				CHECK_ERRORS --no-fail --no-usage || { | ||||
| 					ERROR "with 'strict' settings enabled, context and namespace must be set!" | ||||
| 					REMINDER " | ||||
| 						these values can be set directly with | ||||
| 							$(echo $CLI | head -c1) meta set (namespace|context) | ||||
| 					" | ||||
| @@ -170,16 +171,16 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 
 | ||||
| 			[ $NAMESPACE ] && CLI_ARGS+=(--namespace $NAMESPACE) | ||||
| 			[[ $VERBOSE -eq 1 ]] && { | ||||
| 				echo.reminder " | ||||
| 				REMINDER " | ||||
| 					context '$CONTEXT' | ||||
| 					namespace '$NAMESPACE' | ||||
| 					environment '$SCWRYPTS_ENV' | ||||
| 					subsession '$SUBSESSION' | ||||
| 					" | ||||
| 				echo.status "running $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}" | ||||
| 				STATUS "running $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}" | ||||
| 			} || { | ||||
| 				[[ $(_SCWRYPTS_KUBECTL_SETTINGS get context) =~ ^show$ ]] && { | ||||
| 					echo.reminder "$SCWRYPTS_ENV.$SUBSESSION : $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}" | ||||
| 					REMINDER "$SCWRYPTS_ENV.$SUBSESSION : $CLI ${CLI_ARGS[@]} ${USER_ARGS[@]}" | ||||
| 				} | ||||
| 			} | ||||
| 			$CLI ${CLI_ARGS[@]} ${USER_ARGS[@]} | ||||
| @@ -190,7 +191,7 @@ _SCWRYPTS_KUBECTL_DRIVER() { | ||||
| 
 | ||||
| _SCWRYPTS_KUBECTL_SETTINGS() { | ||||
| 	# (get setting-name) or (set setting-name setting-value) | ||||
| 	kube.redis h$1 ${SCWRYPTS_ENV}:kubectl:settings ${@:2} | grep . | ||||
| 	REDIS h$1 ${SCWRYPTS_ENV}:kubectl:settings ${@:2} | grep . | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| @@ -23,16 +23,16 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__meta() { | ||||
| 	while [[ $# -gt 0 ]] | ||||
| 	do | ||||
| 		case $1 in | ||||
| 			( -h | --help ) HELP=1 ;; | ||||
| 			-h | --help ) HELP=1 ;; | ||||
| 
 | ||||
| 			( set ) | ||||
| 			set )  | ||||
| 				USAGE__usage+=" set" | ||||
| 				USAGE__args="set (namespace|context)" | ||||
| 				USAGE__description="interactively set a namespace or context for '$SCWRYPTS_ENV'" | ||||
| 				case $2 in | ||||
| 					( namespace | context ) USER_ARGS+=($1 $2 $3); [ $3 ] && shift 1 ;; | ||||
| 					( -h | --help ) HELP=1 ;; | ||||
| 					( '' ) | ||||
| 					namespace | context ) USER_ARGS+=($1 $2 $3); [ $3 ] && shift 1 ;; | ||||
| 					-h | --help ) HELP=1 ;; | ||||
| 					'' ) | ||||
| 						: \ | ||||
| 							&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set context \ | ||||
| 							&& SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta set namespace \ | ||||
| @@ -40,40 +40,40 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__meta() { | ||||
| 						return $? | ||||
| 						;; | ||||
| 
 | ||||
| 					( * ) echo.error "cannot set '$2'" ;; | ||||
| 					* ) ERROR "cannot set '$2'" ;; | ||||
| 				esac | ||||
| 				shift 1 | ||||
| 				;; | ||||
| 
 | ||||
| 			( get ) | ||||
| 			get ) | ||||
| 				USAGE__usage+=" get" | ||||
| 				USAGE__args="get (namespace|context|all)" | ||||
| 				USAGE__description="output the current namespace or context for '$SCWRYPTS_ENV'" | ||||
| 				case $2 in | ||||
| 					( namespace | context | all ) USER_ARGS+=($1 $2) ;; | ||||
| 					namespace | context | all ) USER_ARGS+=($1 $2) ;; | ||||
| 
 | ||||
| 					( -h | --help ) HELP=1 ;; | ||||
| 					-h | --help ) HELP=1 ;; | ||||
| 
 | ||||
| 					( * ) echo.error "cannot get '$2'" ;; | ||||
| 					* ) ERROR "cannot get '$2'" ;; | ||||
| 				esac | ||||
| 				shift 1 | ||||
| 				;; | ||||
| 
 | ||||
| 			( copy ) | ||||
| 			copy ) | ||||
| 				USAGE__usage+=" copy" | ||||
| 				USAGE__args+="copy [0-9]" | ||||
| 				USAGE__description="copy current subsession ($SUBSESSION) to target subsession id" | ||||
| 				case $2 in | ||||
| 					( [0-9] ) USER_ARGS+=($1 $2) ;; | ||||
| 					( -h | --help ) HELP=1 ;; | ||||
| 					( * ) echo.error "target session must be a number [0-9]" ;; | ||||
| 					[0-9] ) USER_ARGS+=($1 $2) ;; | ||||
| 					-h | --help ) HELP=1 ;; | ||||
| 					* ) ERROR "target session must be a number [0-9]" ;; | ||||
| 				esac | ||||
| 				shift 1 | ||||
| 				;; | ||||
| 
 | ||||
| 			( clear | show | hide | strict | loose ) USER_ARGS+=($1) ;; | ||||
| 			clear | show | hide | strict | loose ) USER_ARGS+=($1) ;; | ||||
| 
 | ||||
| 			( * ) echo.error "no meta command '$1'" | ||||
| 			* ) ERROR "no meta command '$1'" | ||||
| 		esac | ||||
| 		shift 1 | ||||
| 	done | ||||
| @@ -81,10 +81,10 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND_PARSE__meta() { | ||||
| 
 | ||||
| SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta() { | ||||
| 	case $1 in | ||||
| 		( get ) | ||||
| 		get ) | ||||
| 			[[ $2 =~ ^all$ ]] && { | ||||
| 				local CONTEXT=$(kube.redis get --prefix current:context | grep . || utils.colors.print bright-red "none set") | ||||
| 				local NAMESPACE=$(kube.redis get --prefix current:namespace | grep . || utils.colors.print bright-red "none set") | ||||
| 				local CONTEXT=$(REDIS get --prefix current:context | grep . || echo "\\033[1;31mnone set\\033[0m") | ||||
| 				local NAMESPACE=$(REDIS get --prefix current:namespace | grep . || echo "\\033[1;31mnone set\\033[0m") | ||||
| 				echo " | ||||
| 					environment : $SCWRYPTS_ENV | ||||
| 					context     : $CONTEXT | ||||
| @@ -92,53 +92,51 @@ SCWRYPTS_KUBECTL_CUSTOM_COMMAND__meta() { | ||||
| 
 | ||||
| 					CLI settings | ||||
| 					  command context : $(_SCWRYPTS_KUBECTL_SETTINGS get context) | ||||
| 					      strict mode : $([[ $STRICT -eq 1 ]] && utils.colors.print green on || utils.colors.print bright-red off) | ||||
| 					      strict mode : $([[ $STRICT -eq 1 ]] && echo "on" || echo "\\033[1;31moff\\033[0m") | ||||
| 					" | sed 's/^	\+//' >&2 | ||||
| 				return 0 | ||||
| 			} | ||||
| 
 | ||||
| 			kube.redis get --prefix current:$2 | ||||
| 			REDIS get --prefix current:$2 | ||||
| 			;; | ||||
| 
 | ||||
| 		( set ) | ||||
| 		set ) | ||||
| 			scwrypts -n --name set-$2 --type zsh --group kubectl -- $3 --subsession $SUBSESSION >/dev/null \ | ||||
| 				&& SUCCESS "$2 set" | ||||
| 			;; | ||||
| 
 | ||||
| 		copy ) | ||||
| 			: \ | ||||
| 				&& scwrypts -n --name set-$2 --type zsh --group kube -- $3 --subsession $SUBSESSION >/dev/null \ | ||||
| 				&& k $SUBSESSION meta get $2 \ | ||||
| 				&& STATUS "copying $1 to $2" \ | ||||
| 				&& scwrypts -n --name set-context --type zsh --group kubectl -- --subsession $2 $(k meta get context | grep . || echo 'reset') \ | ||||
| 				&& scwrypts -n --name set-namespace --type zsh --group kubectl -- --subsession $2 $(k meta get namespace | grep . || echo 'reset') \ | ||||
| 				&& SUCCESS "subsession $1 copied to $2" \ | ||||
| 				; | ||||
| 			;; | ||||
| 
 | ||||
| 		( copy ) | ||||
| 			: \ | ||||
| 				&& echo.status "copying $1 to $2" \ | ||||
| 				&& scwrypts -n --name set-context --type zsh --group kube -- --subsession $2 $(k $1 meta get context | grep . || echo 'reset') \ | ||||
| 				&& scwrypts -n --name set-namespace --type zsh --group kube -- --subsession $2 $(k $1 meta get namespace | grep . || echo 'reset') \ | ||||
| 				&& echo.success "subsession $1 copied to $2" \ | ||||
| 				; | ||||
| 		clear ) | ||||
| 			scwrypts -n --name set-context --type zsh --group kubectl -- --subsession $SUBSESSION reset >/dev/null \ | ||||
| 				&& SUCCESS "subsession $SUBSESSION reset to default" | ||||
| 			;; | ||||
| 
 | ||||
| 		( clear ) | ||||
| 			scwrypts -n --name set-context --type zsh --group kube -- --subsession $SUBSESSION reset >/dev/null \ | ||||
| 				&& echo.success "subsession $SUBSESSION reset to default" | ||||
| 			;; | ||||
| 
 | ||||
| 		( show ) | ||||
| 		show ) | ||||
| 			_SCWRYPTS_KUBECTL_SETTINGS set context show >/dev/null \ | ||||
| 				&& echo.success "now showing full command context" | ||||
| 				&& SUCCESS "now showing full command context" | ||||
| 			;; | ||||
| 
 | ||||
| 		( hide ) | ||||
| 		hide ) | ||||
| 			_SCWRYPTS_KUBECTL_SETTINGS set context hide >/dev/null \ | ||||
| 				&& echo.success "now hiding command context" | ||||
| 				&& SUCCESS "now hiding command context" | ||||
| 			;; | ||||
| 
 | ||||
| 		( loose ) | ||||
| 		loose ) | ||||
| 			_SCWRYPTS_KUBECTL_SETTINGS set strict 0 >/dev/null \ | ||||
| 				&& echo.warning "now running in 'loose' mode" | ||||
| 				&& WARNING "now running in 'loose' mode" | ||||
| 			;; | ||||
| 
 | ||||
| 		( strict ) | ||||
| 		strict ) | ||||
| 			_SCWRYPTS_KUBECTL_SETTINGS set strict 1 >/dev/null \ | ||||
| 				&& echo.success "now running in 'strict' mode" | ||||
| 				&& SUCCESS "now running in 'strict' mode" | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use kubectl --group kube | ||||
| #!/bin/zsh | ||||
| use kubectl --group kubectl | ||||
| ##################################################################### | ||||
| 
 | ||||
| MAIN() { | ||||
| 	kube.kubectl.context.get | ||||
| 	KUBECTL__GET_CONTEXT | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use kubectl --group kube | ||||
| #!/bin/zsh | ||||
| use kubectl --group kubectl | ||||
| ##################################################################### | ||||
| 
 | ||||
| MAIN() { | ||||
| 	kube.kubectl.namespace.get | ||||
| 	KUBECTL__GET_NAMESPACE | ||||
| } | ||||
							
								
								
									
										11
									
								
								plugins/kubectl/kubectl.scwrypts.zsh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								plugins/kubectl/kubectl.scwrypts.zsh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| SCWRYPTS_GROUPS+=(kubectl) | ||||
| 
 | ||||
| export SCWRYPTS_TYPE__kubectl=zsh | ||||
| export SCWRYPTS_ROOT__kubectl="$SCWRYPTS_ROOT__scwrypts/plugins/kubectl" | ||||
| export SCWRYPTS_COLOR__kubectl='\033[0;31m' | ||||
| 
 | ||||
| SCWRYPTS_STATIC_CONFIG__kubectl+=( | ||||
| 	"$SCWRYPTS_ROOT__kubectl/.config/static/redis.zsh" | ||||
| ) | ||||
| 
 | ||||
| source "$SCWRYPTS_ROOT__kubectl/driver/kubectl.driver.zsh" | ||||
							
								
								
									
										158
									
								
								plugins/kubectl/lib/kubectl.module.zsh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								plugins/kubectl/lib/kubectl.module.zsh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| DEPENDENCIES+=( | ||||
| 	kubectl | ||||
| ) | ||||
| 
 | ||||
| REQUIRED_ENV+=() | ||||
| 
 | ||||
| use redis --group kubectl | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| KUBECTL() { | ||||
| 	local NAMESPACE=$(REDIS get --prefix "current:namespace") | ||||
| 	local CONTEXT=$(KUBECTL__GET_CONTEXT) | ||||
| 
 | ||||
| 	local KUBECTL_ARGS=() | ||||
| 	[ $NAMESPACE ] && KUBECTL_ARGS+=(--namespace $NAMESPACE) | ||||
| 	[ $CONTEXT   ] && KUBECTL_ARGS+=(--context $CONTEXT) | ||||
| 
 | ||||
| 	kubectl ${KUBECTL_ARGS[@]} $@ | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| KUBECTL__GET_CONTEXT() { REDIS get --prefix "current:context"; } | ||||
| 
 | ||||
| KUBECTL__SET_CONTEXT() { | ||||
| 	local CONTEXT=$1 | ||||
| 	[ ! $CONTEXT ] && return 1 | ||||
| 
 | ||||
| 	[[ $CONTEXT =~ reset ]] && { | ||||
| 		: \ | ||||
| 			&& REDIS del --prefix "current:context" \ | ||||
| 			&& KUBECTL__SET_NAMESPACE reset \ | ||||
| 			; | ||||
| 		return $? | ||||
| 	} | ||||
| 
 | ||||
| 	: \ | ||||
| 		&& REDIS set --prefix "current:context" "$CONTEXT" \ | ||||
| 		&& KUBECTL__SET_NAMESPACE reset \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| KUBECTL__SELECT_CONTEXT() { | ||||
| 	KUBECTL__LIST_CONTEXTS | FZF 'select a context' | ||||
| } | ||||
| 
 | ||||
| KUBECTL__LIST_CONTEXTS() { | ||||
| 	echo reset | ||||
| 	local ALL_CONTEXTS=$(KUBECTL config get-contexts -o name | sort) | ||||
| 
 | ||||
| 	echo $ALL_CONTEXTS | grep -v '^arn:aws:eks' | ||||
| 
 | ||||
| 	[[ $AWS_ACCOUNT ]] && { | ||||
| 		echo $ALL_CONTEXTS | grep "^arn:aws:eks:.*:$AWS_ACCOUNT" | ||||
| 		true | ||||
| 	} || { | ||||
| 		echo $ALL_CONTEXTS | grep '^arn:aws:eks' | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| KUBECTL__GET_NAMESPACE() { REDIS get --prefix "current:namespace"; } | ||||
| 
 | ||||
| KUBECTL__SET_NAMESPACE() { | ||||
| 	local NAMESPACE=$1 | ||||
| 	[ ! $NAMESPACE ] && return 1 | ||||
| 
 | ||||
| 	[[ $NAMESPACE =~ reset ]] && { | ||||
| 		REDIS del --prefix "current:namespace" | ||||
| 		return $? | ||||
| 	} | ||||
| 
 | ||||
| 	REDIS set --prefix "current:namespace" "$NAMESPACE" | ||||
| } | ||||
| 
 | ||||
| KUBECTL__SELECT_NAMESPACE() { | ||||
| 	KUBECTL__LIST_NAMESPACES | FZF 'select a namespace' | ||||
| } | ||||
| 
 | ||||
| KUBECTL__LIST_NAMESPACES() { | ||||
| 	echo reset | ||||
| 	echo default | ||||
| 	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 | ||||
| 
 | ||||
| 	REMINDER "attempting to serve ${NAMESPACE}/${SERVICE_NAME}:${SERVICE_PORT}" | ||||
| 	[ $SERVICE_PASSWORD ] && REMINDER "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|/.*$||') | ||||
| } | ||||
| @@ -5,13 +5,16 @@ DEPENDENCIES+=( | ||||
| 	docker | ||||
| ) | ||||
| 
 | ||||
| REQUIRED_ENV+=() | ||||
| # TODO; allow custom redis configuration | ||||
| export SCWRYPTS_KUBECTL_REDIS=managed | ||||
| 
 | ||||
| utils.environment.check SCWRYPTS_KUBECTL_REDIS --default managed | ||||
| REQUIRED_ENV+=( | ||||
| 	SCWRYPTS_KUBECTL_REDIS | ||||
| ) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| kube.redis() { | ||||
| REDIS() { | ||||
| 	[ ! $USAGE ] && local USAGE=" | ||||
| 		usage: [...options...] | ||||
| 
 | ||||
| @@ -21,7 +24,7 @@ kube.redis() { | ||||
| 		  -p, --prefix   apply dynamic prefix to the next command line argument | ||||
| 
 | ||||
| 		  --get-prefix              output key prefix for current session+subsession | ||||
| 		  --get-static-definition   output the static ZSH function definition for kube.redis | ||||
| 		  --get-static-definition   output the static ZSH function definition for REDIS | ||||
| 
 | ||||
| 		  additional arguments and options are passed through to 'redis-cli' | ||||
| 	" | ||||
| @@ -35,15 +38,15 @@ kube.redis() { | ||||
| 
 | ||||
| 	while [[ $# -gt 0 ]] | ||||
| 	do | ||||
| 		case $1 in | ||||
| 			( -p | --prefix ) USER_ARGS+=("${REDIS_PREFIX}${SCWRYPTS_ENV}:${SUBSESSION}:$2"); shift 1 ;; | ||||
| 		case $1 in  | ||||
| 			-p | --prefix ) USER_ARGS+=("${REDIS_PREFIX}${SCWRYPTS_ENV}:${SUBSESSION}:$2"); shift 1 ;; | ||||
| 
 | ||||
| 			( --subsession            ) SUBSESSION=$2; shift 1 ;; | ||||
| 			--subsession            ) SUBSESSION=$2; shift 1 ;; | ||||
| 
 | ||||
| 			( --get-prefix            ) echo $REDIS_PREFIX; return 0 ;; | ||||
| 			( --get-static-definition ) ECHO_STATIC_DEFINITION=1 ;; | ||||
| 			--get-prefix            ) echo $REDIS_PREFIX; return 0 ;; | ||||
| 			--get-static-definition ) ECHO_STATIC_DEFINITION=1 ;; | ||||
| 
 | ||||
| 			( * ) USER_ARGS+=($1) ;; | ||||
| 			* ) USER_ARGS+=($1) ;; | ||||
| 		esac | ||||
| 		shift 1 | ||||
| 	done | ||||
| @@ -59,14 +62,14 @@ kube.redis() { | ||||
| 	REDIS_ARGS+=(--raw) | ||||
| 
 | ||||
| 	[[ $ECHO_STATIC_DEFINITION -eq 1 ]] && { | ||||
| 		echo "kube.redis() {\ | ||||
| 		echo "REDIS() {\ | ||||
| 			local USER_ARGS=(); \ | ||||
| 			[ ! \$SUBSESSION ] && local SUBSESSION=0 ;\ | ||||
| 			while [[ \$# -gt 0 ]]; \ | ||||
| 			do \ | ||||
| 				case \$1 in | ||||
| 				( -p | --prefix ) USER_ARGS+=(\"${REDIS_PREFIX}\${SCWRYPTS_ENV}:\${SUBSESSION}:\$2\"); shift 1 ;; \ | ||||
| 				( * ) USER_ARGS+=(\$1) ;; \ | ||||
| 				-p | --prefix ) USER_ARGS+=(\"${REDIS_PREFIX}\${SCWRYPTS_ENV}:\${SUBSESSION}:\$2\"); shift 1 ;; \ | ||||
| 				* ) USER_ARGS+=(\$1) ;; \ | ||||
| 				esac; \ | ||||
| 				shift 1; \ | ||||
| 			done; \ | ||||
| @@ -78,9 +81,9 @@ kube.redis() { | ||||
| 	redis-cli ${REDIS_ARGS[@]} ${USER_ARGS[@]} | ||||
| } | ||||
| 
 | ||||
| kube.redis ping 2>/dev/null | grep -qi pong || { | ||||
| REDIS ping | grep -qi pong || { | ||||
| 	RPID=$(docker ps -a | grep scwrypts-kubectl-redis | awk '{print $1;}') | ||||
| 	[ $RPID ] && echo.status 'refreshing redis instance' && docker rm -f $RPID | ||||
| 	[ $RPID ] && STATUS 'refreshing redis instance' && docker rm -f $RPID | ||||
| 	unset RPID | ||||
| 
 | ||||
| 	docker run \ | ||||
| @@ -89,6 +92,6 @@ kube.redis ping 2>/dev/null | grep -qi pong || { | ||||
| 		--publish $SCWRYPTS_KUBECTL_REDIS_PORT__managed:6379 \ | ||||
| 		redis >/dev/null 2>&1 | ||||
| 
 | ||||
| 	echo.status 'awaiting redis connection' | ||||
| 	until kube.redis ping 2>/dev/null | grep -qi pong; do sleep 0.5; done | ||||
| 	STATUS 'awaiting redis connection' | ||||
| 	until REDIS ping 2>/dev/null | grep -qi pong; do sleep 0.5; done | ||||
| } | ||||
							
								
								
									
										7
									
								
								plugins/kubectl/meta/get-static-redis-definition
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								plugins/kubectl/meta/get-static-redis-definition
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/bin/zsh | ||||
| use redis --group kubectl | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	echo $(REDIS --get-static-definition) | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use kubectl --group kube | ||||
| #!/bin/zsh | ||||
| use kubectl --group kubectl | ||||
| ##################################################################### | ||||
| 
 | ||||
| MAIN() { | ||||
| @@ -12,7 +12,7 @@ MAIN() { | ||||
| 	options: | ||||
| 	  --context      override context | ||||
| 	  --namespace    override namespace | ||||
| 	  --subsession   kube.redis subsession (default 0) | ||||
| 	  --subsession   REDIS subsession (default 0) | ||||
| 
 | ||||
| 	  to show a required password on screen, use both: | ||||
| 	  --password-secret   Secret resource | ||||
| @@ -33,17 +33,17 @@ MAIN() { | ||||
| 			--password-secret ) PASSWORD_SECRET=$2; shift 1 ;; | ||||
| 			--password-key    ) PASSWORD_KEY=$2; shift 1 ;; | ||||
| 
 | ||||
| 			-h | --help ) utils.io.usage; return 0 ;; | ||||
| 			-h | --help ) USAGE; return 0 ;; | ||||
| 
 | ||||
| 			* ) | ||||
| 				[ $SERVICE ] && echo.error "unexpected argument '$2'" | ||||
| 				[ $SERVICE ] && ERROR "unexpected argument '$2'" | ||||
| 				SERVICE=$1 | ||||
| 				;; | ||||
| 		esac | ||||
| 		shift 1 | ||||
| 	done | ||||
| 
 | ||||
| 	utils.check-errors --fail | ||||
| 	CHECK_ERRORS | ||||
| 
 | ||||
| 	kube.kubectl.serve | ||||
| 	KUBECTL__SERVE  | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use kubectl --group kube | ||||
| #!/bin/zsh | ||||
| use kubectl --group kubectl | ||||
| ##################################################################### | ||||
| 
 | ||||
| MAIN() { | ||||
| @@ -10,7 +10,7 @@ MAIN() { | ||||
| 	  context   (optional) the full name of the kubeconfig context to set | ||||
| 
 | ||||
| 	options: | ||||
| 	  --subsession   kube.redis subsession (default 0) | ||||
| 	  --subsession   REDIS subsession (default 0) | ||||
| 
 | ||||
| 	  -h, --help   show this dialogue and exit | ||||
| 	" | ||||
| @@ -22,18 +22,20 @@ MAIN() { | ||||
| 		case $1 in | ||||
| 			--subsession ) SUBSESSION=$2; shift 1 ;; | ||||
| 
 | ||||
| 			-h | --help ) USAGE; return 0 ;; | ||||
| 
 | ||||
| 			* ) | ||||
| 				[ $CONTEXT ] && echo.error "unexpected argument '$2'" | ||||
| 				[ $CONTEXT ] && ERROR "unexpected argument '$2'" | ||||
| 				CONTEXT=$1 | ||||
| 				;; | ||||
| 		esac | ||||
| 		shift 1 | ||||
| 	done | ||||
| 
 | ||||
| 	[ $CONTEXT ] || CONTEXT=$(kube.kubectl.context.select) | ||||
| 	[ $CONTEXT ] || echo.error 'must provide or select a valid kube context' | ||||
| 	[ $CONTEXT ] || CONTEXT=$(KUBECTL__SELECT_CONTEXT) | ||||
| 	[ $CONTEXT ] || ERROR 'must provide or select a valid kube context' | ||||
| 
 | ||||
| 	utils.check-errors --fail | ||||
| 	CHECK_ERRORS | ||||
| 
 | ||||
| 	kube.kubectl.context.set $CONTEXT | ||||
| 	KUBECTL__SET_CONTEXT $CONTEXT | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/usr/bin/env zsh | ||||
| use kubectl --group kube | ||||
| #!/bin/zsh | ||||
| use kubectl --group kubectl | ||||
| ##################################################################### | ||||
| 
 | ||||
| MAIN() { | ||||
| @@ -10,7 +10,7 @@ MAIN() { | ||||
| 	  namespace   (optional) the full name of the namespace context to set | ||||
| 
 | ||||
| 	options: | ||||
| 	  --subsession   kube.redis subsession (default 0) | ||||
| 	  --subsession   REDIS subsession (default 0) | ||||
| 
 | ||||
| 	  -h, --help   show this dialogue and exit | ||||
| 	" | ||||
| @@ -22,20 +22,20 @@ MAIN() { | ||||
| 		case $1 in | ||||
| 			--subsession ) SUBSESSION=$2; shift 1 ;; | ||||
| 
 | ||||
| 			-h | --help ) utils.io.usage; return 0 ;; | ||||
| 			-h | --help ) USAGE; return 0 ;; | ||||
| 
 | ||||
| 			* ) | ||||
| 				[ $NAMESPACE ] && echo.error "unexpected argument '$2'" | ||||
| 				[ $NAMESPACE ] && ERROR "unexpected argument '$2'" | ||||
| 				NAMESPACE=$1 | ||||
| 				;; | ||||
| 		esac | ||||
| 		shift 1 | ||||
| 	done | ||||
| 
 | ||||
| 	[ $NAMESPACE ] || NAMESPACE=$(kube.kubectl.namespace.select) | ||||
| 	[ $NAMESPACE ] || echo.error 'must provide or select a valid namespace' | ||||
| 	[ $NAMESPACE ] || NAMESPACE=$(KUBECTL__SELECT_NAMESPACE) | ||||
| 	[ $NAMESPACE ] || ERROR 'must provide or select a valid namespace' | ||||
| 
 | ||||
| 	utils.check-errors --fail | ||||
| 	CHECK_ERRORS | ||||
| 
 | ||||
| 	kube.kubectl.namespace.set $NAMESPACE | ||||
| 	KUBECTL__SET_NAMESPACE $NAMESPACE | ||||
| } | ||||
| @@ -1,27 +1,10 @@ | ||||
| from json import loads | ||||
|  | ||||
| from .scwrypts import scwrypts | ||||
| from os import getenv as os_getenv | ||||
|  | ||||
| from .scwrypts.exceptions import MissingVariableError | ||||
|  | ||||
| ENV = {} | ||||
|  | ||||
| def getenv(name, required=True, default=None): | ||||
|     if ENV.get('configuration') is None or ENV.get('environment') is None: | ||||
|         full_environment = loads( | ||||
|                 scwrypts( | ||||
|                     name = 'scwrypts/environment/getenv', | ||||
|                     group = 'scwrypts', | ||||
|                     _type = 'zsh', | ||||
|                     executable_args = '-n', | ||||
|                     args = '--all', | ||||
|                     ).stdout | ||||
|                 ) | ||||
|  | ||||
|         ENV['configuration'] = full_environment['configuration'] | ||||
|         ENV['environment']   = full_environment['environment'] | ||||
|  | ||||
|     value = ENV.get('environment', {}).get(name, default) | ||||
| def getenv(name, required=True): | ||||
|     value = os_getenv(name, None) | ||||
|  | ||||
|     if required and not value: | ||||
|         raise MissingVariableError(name) | ||||
|   | ||||
| @@ -2,22 +2,23 @@ from types import SimpleNamespace | ||||
|  | ||||
| from pytest import fixture | ||||
|  | ||||
| from scwrypts.test import get_generator | ||||
| from scwrypts.test import generate | ||||
| from scwrypts.test.character_set import uri | ||||
|  | ||||
| generate = get_generator({ | ||||
| options = { | ||||
|         'str_length_minimum':   8, | ||||
|         'str_length_maximum': 128, | ||||
|         'uuid_output_type':   str, | ||||
|         }) | ||||
|         } | ||||
|  | ||||
| def get_request_client_sample_data(): | ||||
|     return { | ||||
|             'base_url' : generate(str, {'character_set': uri}), | ||||
|             'endpoint' : generate(str, {'character_set': uri}), | ||||
|             'method'   : generate(str), | ||||
|             'response' : generate('requests_Response', {'depth': 4}), | ||||
|             'base_url' : generate(str, options | {'character_set': uri}), | ||||
|             'endpoint' : generate(str, options | {'character_set': uri}), | ||||
|             'method'   : generate(str, options), | ||||
|             'response' : generate('requests_Response', options | {'depth': 4}), | ||||
|             'payload'  : generate(dict, { | ||||
|                 **options, | ||||
|                 'depth': 1, | ||||
|                 'data_types': { str, 'uuid' }, | ||||
|                 }), | ||||
| @@ -29,11 +30,13 @@ def fixture_sample(): | ||||
|             **get_request_client_sample_data(), | ||||
|  | ||||
|             headers = generate(dict, { | ||||
|                 **options, | ||||
|                 'depth': 1, | ||||
|                 'data_types': { str, 'uuid' }, | ||||
|                 }), | ||||
|  | ||||
|             payload_headers = generate(dict, { | ||||
|                 **options, | ||||
|                 'depth': 1, | ||||
|                 'data_types': { str, 'uuid' }, | ||||
|                 }), | ||||
|   | ||||
| @@ -2,14 +2,15 @@ from types import SimpleNamespace | ||||
|  | ||||
| from pytest import fixture | ||||
|  | ||||
| from scwrypts.test import generate | ||||
| from scwrypts.test.character_set import uri | ||||
| from ..conftest import generate, get_request_client_sample_data | ||||
| from ..conftest import options, get_request_client_sample_data | ||||
|  | ||||
|  | ||||
| @fixture(name='sample') | ||||
| def fixture_sample(): | ||||
|     return SimpleNamespace( | ||||
|             **get_request_client_sample_data(), | ||||
|             api_token = generate(str, {'character_set': uri}), | ||||
|             query     = generate(str), | ||||
|             api_token = generate(str, options | {'character_set': uri}), | ||||
|             query     = generate(str, options), | ||||
|             ) | ||||
|   | ||||
| @@ -3,8 +3,9 @@ from types import SimpleNamespace | ||||
|  | ||||
| from pytest import fixture | ||||
|  | ||||
| from scwrypts.test import generate | ||||
| from scwrypts.test.character_set import uri | ||||
| from ..conftest import generate, get_request_client_sample_data | ||||
| from ..conftest import options, get_request_client_sample_data | ||||
|  | ||||
| @fixture(name='sample') | ||||
| def fixture_sample(): | ||||
| @@ -13,12 +14,12 @@ def fixture_sample(): | ||||
|                 **get_request_client_sample_data(), | ||||
|                 'base_url': 'https://discord.com/api', | ||||
|                 }, | ||||
|             bot_token  = generate(str, {'character_set': uri}), | ||||
|             username   = generate(str, {'character_set': ascii_letters + digits}), | ||||
|             avatar_url = generate(str, {'character_set': uri}), | ||||
|             webhook    = generate(str, {'character_set': uri}), | ||||
|             channel_id = generate(str, {'character_set': uri}), | ||||
|             content_header = generate(str), | ||||
|             content_footer = generate(str), | ||||
|             content = generate(str), | ||||
|             bot_token  = generate(str, options | {'character_set': uri}), | ||||
|             username   = generate(str, options | {'character_set': ascii_letters + digits}), | ||||
|             avatar_url = generate(str, options | {'character_set': uri}), | ||||
|             webhook    = generate(str, options | {'character_set': uri}), | ||||
|             channel_id = generate(str, options | {'character_set': uri}), | ||||
|             content_header = generate(str, options), | ||||
|             content_footer = generate(str, options), | ||||
|             content = generate(str, options), | ||||
|         ) | ||||
|   | ||||
| @@ -5,7 +5,7 @@ from pytest import fixture | ||||
| from .client import request | ||||
|  | ||||
|  | ||||
| def test_discord_request(sample, _mock_getenv, _response): | ||||
| def test_discord_request(sample, _response): | ||||
|     assert _response == sample.response | ||||
|  | ||||
| def test_discord_request_client_setup(sample, mock_get_request_client, _mock_getenv, _response): | ||||
| @@ -41,7 +41,7 @@ def fixture_mock_get_request_client(sample): | ||||
|  | ||||
| @fixture(name='_mock_getenv') | ||||
| def fixture_mock_getenv(sample): | ||||
|     with patch('scwrypts.http.discord.client.getenv') as mock: | ||||
|     with patch('scwrypts.http.discord.client.getenv',) as mock: | ||||
|         mock.side_effect = lambda name, **kwargs: { | ||||
|                 'DISCORD__BOT_TOKEN': sample.bot_token, | ||||
|                 }[name] | ||||
| @@ -49,6 +49,6 @@ def fixture_mock_getenv(sample): | ||||
|  | ||||
| @fixture(name='_mock_getenv_optional') | ||||
| def fixture_mock_getenv_optional(): | ||||
|     with patch('scwrypts.http.discord.client.getenv') as mock: | ||||
|     with patch('scwrypts.http.discord.client.getenv',) as mock: | ||||
|         mock.side_effect = lambda name, **kwargs: None | ||||
|         yield mock | ||||
|   | ||||
| @@ -3,8 +3,9 @@ from types import SimpleNamespace | ||||
|  | ||||
| from pytest import fixture | ||||
|  | ||||
| from scwrypts.test import generate | ||||
| from scwrypts.test.character_set import uri | ||||
| from ..conftest import generate, get_request_client_sample_data | ||||
| from ..conftest import options, get_request_client_sample_data | ||||
|  | ||||
| @fixture(name='sample') | ||||
| def fixture_sample(): | ||||
| @@ -13,6 +14,6 @@ def fixture_sample(): | ||||
|                 **get_request_client_sample_data(), | ||||
|                 'base_url': 'https://api.linear.app', | ||||
|                 }, | ||||
|             api_token = generate(str, {'character_set': uri}), | ||||
|             query     = generate(str), | ||||
|             api_token = generate(str, options | {'character_set': uri}), | ||||
|             query     = generate(str, options), | ||||
|         ) | ||||
|   | ||||
| @@ -4,11 +4,9 @@ from json import dumps, loads | ||||
| from random import randint, uniform, choice | ||||
| from re import sub | ||||
| from string import printable | ||||
| from typing import Callable | ||||
| from typing import Hashable, Callable | ||||
| from uuid import uuid4 | ||||
|  | ||||
| from collections.abc import Hashable | ||||
|  | ||||
| from requests import Response, status_codes | ||||
| from yaml import safe_dump | ||||
|  | ||||
|   | ||||
							
								
								
									
										472
									
								
								scwrypts
									
									
									
									
									
								
							
							
						
						
									
										472
									
								
								scwrypts
									
									
									
									
									
								
							| @@ -1,16 +1,16 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| export EXECUTION_DIR=$(pwd) | ||||
| export SCWRYPTS_RUNTIME_ID=$(uuidgen) | ||||
| source "$(dirname -- $(readlink -f -- "$0"))/zsh/import.driver.zsh" || return 42 | ||||
|  | ||||
| use scwrypts/environment | ||||
| use scwrypts/list-available | ||||
| use scwrypts/get-runstring | ||||
|  | ||||
| source "$(dirname $(readlink -f "$0"))/zsh/lib/import.driver.zsh" || exit 42 | ||||
| ##################################################################### | ||||
| () { | ||||
| 	cd "$(scwrypts.config.group scwrypts root)" | ||||
| 	GIT_SCWRYPTS() { git -C "$(scwrypts.config.group scwrypts root)" $@; } | ||||
| 	cd "$SCWRYPTS_ROOT__scwrypts" | ||||
| 	GIT_SCWRYPTS() { git -C "$SCWRYPTS_ROOT__scwrypts" $@; } | ||||
|  | ||||
| 	local INSTALLATION_TYPE | ||||
| 	[ ! -d "$SCWRYPTS_ROOT__scwrypts/.git" ] && [ ! -f "$SCWRYPTS_ROOT__scwrypts/.git" ] \ | ||||
| 		&& INSTALLATION_TYPE=$(cat "$SCWRYPTS_ROOT__scwrypts/MANAGED_BY" 2>/dev/null) \ | ||||
| 		|| INSTALLATION_TYPE=manual \ | ||||
| 		; | ||||
|  | ||||
| 	local ERRORS=0 | ||||
| 	local USAGE=' | ||||
| @@ -26,26 +26,20 @@ use scwrypts/get-runstring | ||||
| 		  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 incremental scwrypts log level to one of the following: | ||||
| 		                              0 : only command output and critical failures; skips logfile | ||||
| 		                              1 : include success / failure messages | ||||
| 		                              2 : include status update messages | ||||
| 		                              3 : (default) include warning messages | ||||
| 		                              4 : include debug messages | ||||
|  | ||||
| 		     -o, --output <format>   specify output format; one of: pretty,json (default: pretty) | ||||
| 		    -n                     shorthand for "--log-level 0" | ||||
| 		    -v, --log-level [0-4]  set incremental scwrypts log level to one of the following: | ||||
| 			                         0 : only command output and critical failures; skips logfile | ||||
| 			                         1 : include success / failure messages | ||||
| 			                         2 : include status update messages | ||||
| 									 3 : (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 | ||||
| 		        --list-groups   print out configured scwrypts groups and exit | ||||
| 		        --config        "eval"-ed to enable config and "use" import in non-scwrypts environments | ||||
| 		        --root          print out scwrypts.config.group.scwrypts.root and exit | ||||
| 		        --update        update scwrypts library to latest version | ||||
| 		        --version       print out scwrypts version and exit | ||||
| 		    -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 | ||||
| @@ -59,78 +53,55 @@ use scwrypts/get-runstring | ||||
| 	### cli argument parsing and global configuration ################### | ||||
| 	##################################################################### | ||||
|  | ||||
| 	local ENV_NAME="${SCWRYPTS_ENV}" | ||||
| 	local ENV_NAME="$SCWRYPTS_ENV" | ||||
| 	local SEARCH_PATTERNS=() | ||||
|  | ||||
| 	local VARSPLIT SEARCH_GROUP SEARCH_TYPE SEARCH_NAME | ||||
|  | ||||
| 	[ ! ${SCWRYPTS_LOG_LEVEL} ] && local SCWRYPTS_LOG_LEVEL=3 | ||||
| 	[ ! $SCWRYPTS_LOG_LEVEL ] && local SCWRYPTS_LOG_LEVEL=3 | ||||
|  | ||||
| 	local SHIFT_COUNT | ||||
| 	while [[ $# -gt 0 ]] | ||||
| 	do | ||||
| 		SHIFT_COUNT=1 | ||||
| 		case $1 in | ||||
| 			( -[a-z][a-z]* ) | ||||
| 			-[a-z][a-z]* ) | ||||
| 				VARSPLIT=$(echo "$1 " | sed 's/^\(-.\)\(.*\) /\1 -\2/') | ||||
| 				set -- throw-away $(echo " ${VARSPLIT} ") ${@:2} | ||||
| 				set -- throw-away $(echo " $VARSPLIT ") ${@:2} | ||||
| 				;; | ||||
|  | ||||
| 			### alternate commands ################### | ||||
|  | ||||
| 			( -h | --help ) | ||||
| 				utils.io.usage | ||||
| 			-h | --help ) | ||||
| 				USAGE | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( -l | --list ) | ||||
| 				scwrypts.list-available | ||||
| 			-l | --list ) | ||||
| 				SCWRYPTS__GET_AVAILABLE_SCWRYPTS | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --list-envs ) | ||||
| 				scwrypts.environment.common.get-env-names | ||||
| 			--list-envs ) | ||||
| 				SCWRYPTS__GET_ENV_NAMES | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --list-groups ) | ||||
| 				echo "${SCWRYPTS_GROUPS[@]}" | sed 's/\s\+/\n/g' | sort -u | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --version ) | ||||
| 				case ${SCWRYPTS_INSTALLATION_TYPE} in | ||||
| 					( manual ) echo "scwrypts $(GIT_SCWRYPTS describe --tags) (via GIT)" ;; | ||||
| 					( *      ) echo "scwrypts $(cat "$(scwrypts.config.group scwrypts root)/VERSION")" ;; | ||||
| 			--version ) | ||||
| 				case $INSTALLATION_TYPE in | ||||
| 					manual ) echo "scwrypts $(GIT_SCWRYPTS describe --tags) (via GIT)" ;; | ||||
| 					     * ) echo scwrypts $(cat "$SCWRYPTS_ROOT__scwrypts/VERSION")   ;; | ||||
| 				esac | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --root ) | ||||
| 				scwrypts.config.group scwrypts root | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --config ) | ||||
| 				echo "source '$(scwrypts.config.group scwrypts root)/zsh/import.driver.zsh'" | ||||
| 				echo "utils.check-environment --no-fail --no-usage" | ||||
| 				echo "unset __SCWRYPT" | ||||
| 				return 0 | ||||
| 				;; | ||||
|  | ||||
| 			( --update ) | ||||
| 				case ${SCWRYPTS_INSTALLATION_TYPE} in | ||||
| 			--update ) | ||||
| 				case $INSTALLATION_TYPE in | ||||
| 					aur ) | ||||
| 						echo.reminder --force-print " | ||||
| 						SCWRYPTS_LOG_LEVEL=3 REMINDER "  | ||||
| 							This installation is built from the AUR. Update through 'makepkg' or use | ||||
| 							your preferred AUR package management tool (e.g. 'yay -Syu scwrypts') | ||||
| 							 " | ||||
| 						;; | ||||
|  | ||||
| 					homebrew ) | ||||
| 						echo.reminder --force-print "This installation is managed by homebrew. Update me with 'brew update'" | ||||
| 						;; | ||||
|  | ||||
| 					manual ) | ||||
| 						GIT_SCWRYPTS fetch --quiet origin main | ||||
| 						GIT_SCWRYPTS fetch --quiet origin main --tags | ||||
| @@ -139,22 +110,22 @@ use scwrypts/get-runstring | ||||
| 						GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1 | ||||
| 						local DIFF_STATUS=$? | ||||
|  | ||||
| 						[[ ${SYNC_STATUS} -eq 0 ]] && [[ ${DIFF_STATUS} -eq 0 ]] && { | ||||
| 							echo.success 'already up-to-date with origin/main' | ||||
| 						[[ $SYNC_STATUS -eq 0 ]] && [[ $DIFF_STATUS -eq 0 ]] && { | ||||
| 							SUCCESS 'already up-to-date with origin/main' | ||||
| 						} || { | ||||
| 							GIT_SCWRYPTS rebase --autostash origin/main \ | ||||
| 								&& echo.success 'up-to-date with origin/main' \ | ||||
| 								&& SUCCESS 'up-to-date with origin/main' \ | ||||
| 								&& GIT_SCWRYPTS log -n1 \ | ||||
| 								|| { | ||||
| 									GIT_SCWRYPTS rebase --abort | ||||
| 									echo.error 'unable to update scwrypts; please try manual upgrade' | ||||
| 									echo.reminder "installation in '$(scwrypts.config.group scwrypts root)'" | ||||
| 									ERROR 'unable to update scwrypts; please try manual upgrade' | ||||
| 									REMINDER "installation in '$SCWRYPTS_ROOT__scwrypts'" | ||||
| 								} | ||||
| 						} | ||||
| 						;; | ||||
|  | ||||
| 					* ) | ||||
| 						echo.reminder --force-print " | ||||
| 						SCWRYPTS_LOG_LEVEL=3 REMINDER "  | ||||
| 							This is a managed installation of scwrypts. Please update through your | ||||
| 							system package manager. | ||||
| 							 " | ||||
| @@ -165,236 +136,213 @@ use scwrypts/get-runstring | ||||
|  | ||||
| 			### scwrypts filters ##################### | ||||
|  | ||||
| 			( -m | --name ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				[ $2 ] || { echo.error "missing value for argument $1"; break; } | ||||
| 			-m | --name ) | ||||
| 				[ $2 ] || { ERROR "missing value for argument $1"; break; } | ||||
| 				SEARCH_NAME=$2 | ||||
| 				shift 1 | ||||
| 				;; | ||||
|  | ||||
| 			( -g | --group ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				[ $2 ] || { echo.error "missing value for argument $1"; break; } | ||||
| 			-g | --group ) | ||||
| 				[ $2 ] || { ERROR "missing value for argument $1"; break; } | ||||
| 				SEARCH_GROUP=$2 | ||||
| 				GROUP=$2 | ||||
| 				shift 1 | ||||
| 				;; | ||||
|  | ||||
| 			( -t | --type ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				[ $2 ] || { echo.error "missing value for argument $1"; break; } | ||||
| 			-t | --type ) | ||||
| 				[ $2 ] || { ERROR "missing value for argument $1"; break; } | ||||
| 				SEARCH_TYPE=$2 | ||||
| 				TYPE=$2 | ||||
| 				shift 1 | ||||
| 				;; | ||||
|  | ||||
| 			### runtime settings ##################### | ||||
|  | ||||
| 			( -y | --yes ) export __SCWRYPTS_YES=1 ;; | ||||
| 			-y | --yes ) export __SCWRYPTS_YES=1 ;; | ||||
|  | ||||
| 			( -n ) SCWRYPTS_LOG_LEVEL=0 ;; | ||||
| 			-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 ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				[[ $2 =~ ^[0-4]$ ]] || echo.error "invalid setting for log-level '$2'" | ||||
| 			-v | --log-level ) | ||||
| 				[[ $2 =~ ^[0-4]$ ]] || ERROR "invalid setting for log-level '$2'" | ||||
| 				SCWRYPTS_LOG_LEVEL=$2 | ||||
| 				shift 1 | ||||
| 				;; | ||||
|  | ||||
| 			( -o | --output ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				export SCWRYPTS_OUTPUT_FORMAT=$2 | ||||
| 				case ${SCWRYPTS_OUTPUT_FORMAT} in | ||||
| 					( pretty | json ) ;; | ||||
| 					* ) echo.error "unsupported format '${SCWRYPTS_OUTPUT_FORMAT}'" ;; | ||||
| 				esac | ||||
| 				;; | ||||
| 			-e | --env ) | ||||
| 				[ $2 ] || { ERROR "missing value for argument $1"; break; } | ||||
|  | ||||
| 			( -e | --env ) | ||||
| 				((SHIFT_COUNT+=1)) | ||||
| 				[ $2 ] || { echo.error "missing value for argument $1"; break; } | ||||
|  | ||||
| 				[ ${ENV_NAME} ] && echo.debug 'overwriting session environment' | ||||
| 				[ $ENV_NAME ] && DEBUG 'overwriting session environment' | ||||
|  | ||||
| 				ENV_NAME="$2" | ||||
| 				echo.status "using CLI environment '${ENV_NAME}'" | ||||
| 				STATUS "using CLI environment '$ENV_NAME'" | ||||
| 				shift 1 | ||||
| 				;; | ||||
|  | ||||
| 			########################################## | ||||
|  | ||||
| 			( --  ) shift 1; break ;; # pass arguments after '--' to the scwrypt | ||||
| 			( --* ) echo.error "unrecognized argument '$1'" ;; | ||||
| 			( *   ) SEARCH_PATTERNS+=($1) ;; | ||||
| 			--  ) shift 1; break ;; # pass arguments after '--' to the scwrypt | ||||
| 			--* ) ERROR "unrecognized argument '$1'" ;; | ||||
| 			*   ) SEARCH_PATTERNS+=($1) ;; | ||||
| 		esac | ||||
| 		[[ ${SHIFT_COUNT} -le $# ]] \ | ||||
| 			&& shift ${SHIFT_COUNT} \ | ||||
| 			|| echo.error "missing argument for '$1'" \ | ||||
| 			|| shift $# \ | ||||
| 			; | ||||
| 		shift 1 | ||||
| 	done | ||||
|  | ||||
| 	[ ${SCWRYPTS_OUTPUT_FORMAT} ] || export SCWRYPTS_OUTPUT_FORMAT=pretty | ||||
|  | ||||
| 	[ ${SEARCH_NAME} ] && { | ||||
| 		[ ${SEARCH_TYPE}  ] || echo.error '--name requires --type argument' | ||||
| 		[ ${SEARCH_GROUP} ] || echo.error '--name requires --group argument' | ||||
| 	[ $SEARCH_NAME ] && { | ||||
| 		[ $SEARCH_TYPE  ] || ERROR '--name requires --type argument' | ||||
| 		[ $SEARCH_GROUP ] || ERROR '--name requires --group argument' | ||||
| 	} | ||||
|  | ||||
| 	utils.check-errors --fail | ||||
|  | ||||
| 	CHECK_ERRORS | ||||
|  | ||||
| 	##################################################################### | ||||
| 	### scwrypts selection / filtering ################################## | ||||
| 	##################################################################### | ||||
|  | ||||
| 	local SCWRYPTS_AVAILABLE=$(scwrypts.list-available) | ||||
| 	local SCWRYPTS_AVAILABLE | ||||
| 	SCWRYPTS_AVAILABLE=$(SCWRYPTS__GET_AVAILABLE_SCWRYPTS) | ||||
|  | ||||
| 	########################################## | ||||
|  | ||||
| 	[ ${SEARCH_NAME} ] && SCWRYPTS_AVAILABLE=$({ | ||||
| 		echo ${SCWRYPTS_AVAILABLE} | head -n1 | ||||
| 		echo ${SCWRYPTS_AVAILABLE} | utils.colors.remove | grep "^${SEARCH_NAME} *${SEARCH_TYPE} *${SEARCH_GROUP}\$" | ||||
| 	[ $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} ] && { | ||||
| 		[ $SEARCH_TYPE ] && { | ||||
| 			SCWRYPTS_AVAILABLE=$(\ | ||||
| 				{ | ||||
| 					echo ${SCWRYPTS_AVAILABLE} | head -n1 | ||||
| 					echo ${SCWRYPTS_AVAILABLE} | grep ' [^/]*'${SEARCH_TYPE}'[^/]* ' | ||||
| 					echo $SCWRYPTS_AVAILABLE | head -n1 | ||||
| 					echo $SCWRYPTS_AVAILABLE | grep ' [^/]*'$SEARCH_TYPE'[^/]* ' | ||||
| 				} \ | ||||
| 				| sed 's/ \+$/'$(utils.colors.reset)'/; s/ \+/^/g'  \ | ||||
| 				| awk '{$2=""; print $0;}' \ | ||||
| 				| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g'  \ | ||||
| 				| column -ts '^' | ||||
| 			) | ||||
| 		} | ||||
|  | ||||
| 		[ ${SEARCH_GROUP} ] && { | ||||
| 		[ $SEARCH_GROUP ] && { | ||||
| 			SCWRYPTS_AVAILABLE=$( | ||||
| 				{ | ||||
| 					echo ${SCWRYPTS_AVAILABLE} | head -n1 | ||||
| 					echo ${SCWRYPTS_AVAILABLE} | grep "${SEARCH_GROUP}"'[^/ 	]*$' | ||||
| 					echo $SCWRYPTS_AVAILABLE | head -n1 | ||||
| 					echo $SCWRYPTS_AVAILABLE | grep "$SEARCH_GROUP"'[^/]*$' | ||||
| 				} \ | ||||
| 				| sed 's/ \+$/'$(utils.colors.reset)'/; s/ \+/^/g'  \ | ||||
| 				| awk '{$NF=""; print $0;}' \ | ||||
| 				| sed 's/ \+$/'$(printf $__COLOR_RESET)'/; s/ \+/^/g'  \ | ||||
| 				| column -ts '^' | ||||
| 			) | ||||
| 		} | ||||
|  | ||||
| 		[[ ${#SEARCH_PATTERNS[@]} -gt 0 ]] && { | ||||
| 			POTENTIAL_ERROR+="\n   PATTERNS : ${SEARCH_PATTERNS}" | ||||
| 			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} | ||||
| 						echo $SCWRYPTS_AVAILABLE | head -n1 | ||||
| 						echo $SCWRYPTS_AVAILABLE | grep $P | ||||
| 					} | ||||
| 				) | ||||
| 			done | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	[[ $(echo ${SCWRYPTS_AVAILABLE} | wc -l) -lt 2 ]] && { | ||||
| 		utils.fail 1 "$(echo " | ||||
| 	[[ $(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}' | ||||
| 		  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} | utils.fzf "select a script to run" --header-lines 1) \ | ||||
| 	[[ $(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} ] || utils.abort | ||||
| 	[ $SCWRYPT_SELECTION ] || exit 2 | ||||
|  | ||||
| 	########################################## | ||||
|  | ||||
| 	() { | ||||
| 		set -- $(echo $@ | utils.colors.remove) | ||||
| 		export SCWRYPT_NAME=$1 | ||||
| 		export SCWRYPT_TYPE=$2 | ||||
| 		export SCWRYPT_GROUP=$3 | ||||
| 	} ${SCWRYPT_SELECTION} | ||||
| 	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 ]] \ | ||||
| 		&& [ ! $CI ] \ | ||||
| 		&& [[ ! $SCWRYPT_NAME =~ scwrypts/logs ]] \ | ||||
| 		&& [[ ! $SCWRYPT_NAME =~ scwrypts/environment ]] \ | ||||
| 		|| ENV_REQUIRED=false | ||||
|  | ||||
| 	local REQUIRED_ENVIRONMENT_REGEX="$(scwrypts.config.group ${SCWRYPT_GROUP} required_environment_regex)" | ||||
| 	local REQUIRED_ENVIRONMENT_REGEX=$(eval echo '$SCWRYPTS_REQUIRED_ENVIRONMENT_REGEX__'$SCWRYPT_GROUP) | ||||
|  | ||||
| 	[ ${ENV_NAME} ] && [ ${REQUIRED_ENVIRONMENT_REGEX} ] && { | ||||
| 		[[ ${ENV_NAME} =~ ${REQUIRED_ENVIRONMENT_REGEX} ]] \ | ||||
| 			|| utils.fail 5 "group '${SCWRYPT_GROUP}' requires current environment name to match '${REQUIRED_ENVIRONMENT_REGEX}' (currently ${ENV_NAME})" | ||||
| 	[ $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)" | ||||
| 	} | ||||
|  | ||||
| 	[[ ${ENV_REQUIRED} =~ true ]] && { | ||||
| 		[ ! ${ENV_NAME} ] && { | ||||
| 			scwrypts.environment.init \ | ||||
| 				|| echo.error "failed to initialize scwrypts environments (see above)" \ | ||||
| 				|| return 1 \ | ||||
| 				; | ||||
|  | ||||
| 			ENV_NAME=$(scwrypts.environment.select-env) | ||||
| 			[ "${ENV_NAME}" ] || user.abort | ||||
| 		} | ||||
| 	[[ $ENV_REQUIRED =~ true ]] && { | ||||
| 		[ ! $ENV_NAME ] && ENV_NAME=$(SCWRYPTS__SELECT_ENV) | ||||
|  | ||||
| 		for GROUP in ${SCWRYPTS_GROUPS[@]} | ||||
| 		do | ||||
| 			local REQUIRED_REGEX="$(scwrypts.config.group ${GROUP} required_environment_regex)" | ||||
| 			[ ${REQUIRED_REGEX} ] && { | ||||
| 				[[ ${ENV_NAME} =~ ${REQUIRED_REGEX} ]] || continue | ||||
| 			} | ||||
| 			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 $(find "$(scwrypts.config.group ${GROUP} root)/.config/static" -type f 2>/dev/null) | ||||
| 			for f in $(eval 'echo $SCWRYPTS_STATIC_CONFIG__'$GROUP) | ||||
| 			do | ||||
| 				source "${f}" || utils.fail 5 "invalid static config '${f}'" | ||||
| 				source "$f" || FAIL 5 "invalid static config '$f'" | ||||
| 			done | ||||
| 		done | ||||
|  | ||||
| 		export ENV_NAME | ||||
| 	} | ||||
|  | ||||
| 	[ ${REQUIRED_ENVIRONMENT_REGEX} ] && { | ||||
| 		[[ ${ENV_NAME} =~ ${REQUIRED_ENVIRONMENT_REGEX} ]] \ | ||||
| 			|| utils.fail 5 "group '${SCWRYPT_GROUP}' requires current environment name to match '${REQUIRED_ENVIRONMENT_REGEX}' (currently ${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)" | ||||
| 	} | ||||
|  | ||||
| 	export SCWRYPTS_ENV=${ENV_NAME} | ||||
|  | ||||
| 	########################################## | ||||
|  | ||||
| 	[ ! ${SUBSCWRYPT} ] && export SUBSCWRYPT=0 | ||||
| 	[ ! $SUBSCWRYPT ] && export SUBSCWRYPT=0 | ||||
|  | ||||
| 	[[ ${SCWRYPTS_INSTALLATION_TYPE} =~ ^manual$ ]] && { | ||||
| 		[[ ${SUBSCWRYPT} -eq 0 ]] && [[ ${SCWRYPTS_ENV} =~ prod ]] && [[ ${SCWRYPTS_LOG_LEVEL} -gt 0 ]] && { | ||||
| 			echo.status "on '${SCWRYPTS_ENV}'; checking diff against origin/main" | ||||
| 	[[ $INSTALLATION_TYPE =~ ^manual$ ]] && { | ||||
| 		[[ $SUBSCWRYPT -eq 0 ]] && [[ $ENV_NAME =~ prod ]] && [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] && { | ||||
| 			STATUS "on '$ENV_NAME'; checking diff against origin/main" | ||||
|  | ||||
| 			local WARNING_MESSAGE | ||||
|  | ||||
| 			[ ! ${WARNING_MESSAGE} ] && { | ||||
| 			[ ! $WARNING_MESSAGE ] && { | ||||
| 				GIT_SCWRYPTS fetch --quiet origin main \ | ||||
| 					|| WARNING_MESSAGE='I am unable to verify your scwrypts version' | ||||
| 			} | ||||
|  | ||||
| 			[ ! ${WARNING_MESSAGE} ] && { | ||||
| 			[ ! $WARNING_MESSAGE ] && { | ||||
| 				GIT_SCWRYPTS diff --exit-code origin/main -- . >/dev/null 2>&1 \ | ||||
| 					|| WARNING_MESSAGE='your scwrypts is currently out-of-date' | ||||
| 			} | ||||
|  | ||||
| 			[ ${WARNING_MESSAGE} ] && { | ||||
| 				[[ ${SCWRYPTS_LOG_LEVEL} -lt 3 ]] && { | ||||
| 					echo.reminder "you are running in $(utils.colors.bright-red)production$(utils.colors.bright-magenta) and ${WARNING_MESSAGE}" | ||||
| 			[ $WARNING_MESSAGE ] && { | ||||
| 				[[ $SCWRYPTS_LOG_LEVEL -lt 3 ]] && { | ||||
| 					REMINDER "you are running in ${__BRIGHT_RED}production${__BRIGHT_MAGENTA} and $WARNING_MESSAGE" | ||||
| 				} || { | ||||
| 					GIT_SCWRYPTS diff --exit-code origin/main -- . >&2 | ||||
| 					echo.warning "you are trying to run in $(utils.colors.bright-red)production$(echo.warning.color) but ${WARNING_MESSAGE} (relevant diffs and errors above)" | ||||
| 					WARNING "you are trying to run in ${__BRIGHT_RED}production${__YELLOW} but $WARNING_MESSAGE (relevant diffs and errors above)" | ||||
| 					yN 'continue?' || { | ||||
| 						echo.reminder "you can use 'scwrypts --update' to quickly update scwrypts to latest" | ||||
| 						user.abort | ||||
| 						REMINDER "you can use 'scwrypts --update' to quickly update scwrypts to latest" | ||||
| 						ABORT | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| @@ -403,123 +351,75 @@ use scwrypts/get-runstring | ||||
|  | ||||
| 	########################################## | ||||
|  | ||||
| 	local RUN_STRING=$(scwrypts.get-runstring ${SCWRYPT_NAME} ${SCWRYPT_TYPE} ${SCWRYPT_GROUP}) | ||||
| 	[ "${RUN_STRING}" ] || return 42 | ||||
|  | ||||
| 	local RUN_STRING=$(SCWRYPTS__GET_RUNSTRING $SCWRYPT_NAME $SCWRYPT_TYPE $SCWRYPT_GROUP) | ||||
| 	[ "$RUN_STRING" ] || return 42 | ||||
|  | ||||
| 	##################################################################### | ||||
| 	### logging and pretty header/footer setup ########################## | ||||
| 	##################################################################### | ||||
|  | ||||
| 	local RUN_MODE=normal | ||||
| 	[[ ${SCWRYPT_NAME} =~ interactive ]] && RUN_MODE=interactive | ||||
|  | ||||
| 	local LOGFILE \ | ||||
| 		&& [[ ${RUN_MODE} =~ normal ]] \ | ||||
| 		&& [[ ${SCWRYPTS_LOG_LEVEL} -gt 0 ]] \ | ||||
| 		&& [[ ${SUBSCWRYPT} -eq 0 ]] \ | ||||
| 		&& [[ ! ${SCWRYPT_NAME} =~ scwrypts/logs ]] \ | ||||
| 		&& LOGFILE="${SCWRYPTS_LOG_PATH}/$(echo ${GROUP}/${TYPE}/${NAME} | sed 's/^\.\///; s/\//\%/g').log" \ | ||||
| 		&& [[ $SCWRYPTS_LOG_LEVEL -gt 0 ]] \ | ||||
| 		&& [[ $SUBSCWRYPT -eq 0 ]] \ | ||||
| 		&& [[ ! $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 ]] && { | ||||
| 		case ${SCWRYPTS_OUTPUT_FORMAT} in | ||||
| 			( raw ) | ||||
| 				HEADER="--- start scwrypt ${SCWRYPT_GROUP}/${SCWRYPT_TYPE} ${SCWRYPT_NAME} in ${SCWRYPTS_ENV} ---" | ||||
| 				FOOTER="--- end scwrypt ---" | ||||
| 				;; | ||||
| 			( pretty ) | ||||
| 				HEADER=$( | ||||
| 					echo " | ||||
| 						===================================================================== | ||||
| 						scwrypt   : ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME} | ||||
| 						run at    : $(date) | ||||
| 						config    : ${SCWRYPTS_ENV} | ||||
| 						log level : ${SCWRYPTS_LOG_LEVEL} | ||||
| 						$(utils.colors.print bright-yellow '--- SCWRYPT BEGIN ---------------------------------------------------') | ||||
| 					" | sed 's/^\s\+//; 1d' | ||||
| 				) | ||||
|  | ||||
| 				FOOTER="$(utils.colors.print bright-yellow '--- SCWRYPT END   ---------------------------------------------------')" | ||||
| 				;; | ||||
| 			( json ) | ||||
| 				HEADER=$(echo '{}' | jq -c ". | ||||
| 					| .timestamp  = \"$(date +%s)\" | ||||
| 					| .runtime    = \"${SCWRYPTS_RUNTIME_ID}\" | ||||
| 					| .scwrypt    = \"start of ${SCWRYPT_NAME} ${SCWRYPT_GROUP} ${SCWRYPT_TYPE}\" | ||||
| 					| .config     = \"${SCWRYPTS_ENV}\" | ||||
| 					| .logLevel   = \"${SCWRYPTS_LOG_LEVEL}\" | ||||
| 					| .subscwrypt = ${SUBSCWRYPT} | ||||
| 					") | ||||
| 				;; | ||||
| 		esac | ||||
| 	[[ $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} -eq 0 ]] || { | ||||
| 		case ${SCWRYPTS_OUTPUT_FORMAT} in | ||||
| 			( pretty ) | ||||
| 				HEADER="$(utils.colors.print yellow "--- (${SUBSCWRYPT}) BEGIN ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME} ---")" | ||||
| 				FOOTER="$(utils.colors.print yellow "--- (${SUBSCWRYPT}) END   ${SCWRYPT_GROUP} ${SCWRYPT_TYPE} ${SCWRYPT_NAME} ---")" | ||||
| 				;; | ||||
| 		esac | ||||
| 	[[ $SUBSCWRYPT -eq 0 ]] || { | ||||
| 		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 ################################################# | ||||
| 	##################################################################### | ||||
|  | ||||
| 	set -o pipefail | ||||
| 	{ | ||||
| 		[[ ${SCWRYPTS_LOG_LEVEL} -ge 2 ]] && __SCWRYPTS_PRINT_EXIT_CODE=true | ||||
| 		[ $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' | ||||
|  | ||||
| 		[ ${HEADER} ] && echo ${HEADER} >&2 | ||||
| 		[[ $SCWRYPTS_LOG_LEVEL -ge 2 ]] && [ ! $SUBSCWRYPT ] \ | ||||
| 			&& echo "terminated with\\033[1;$EXIT_COLOR code $EXIT_CODE\\033[0m" | ||||
|  | ||||
| 		( | ||||
| 			case ${RUN_MODE} in | ||||
| 				( normal ) | ||||
| 					eval "${RUN_STRING} $(printf "%q " "$@")" | ||||
| 					;; | ||||
| 				( interactive ) | ||||
| 					eval "${RUN_STRING} $(printf "%q " "$@")" </dev/tty &>/dev/tty | ||||
| 					;; | ||||
| 			esac | ||||
| 		) | ||||
|  | ||||
| 		EXIT_CODE=$? | ||||
|  | ||||
| 		[ ${FOOTER} ] && echo ${FOOTER} >&2 | ||||
|  | ||||
| 		[[ ${__SCWRYPTS_PRINT_EXIT_CODE} =~ true ]] && { | ||||
| 			EXIT_COLOR=$( [[ ${EXIT_CODE} -eq 0 ]] && utils.colors.bright-green || utils.colors.bright-red ) | ||||
| 			case ${SCWRYPTS_OUTPUT_FORMAT} in | ||||
| 				( raw ) | ||||
| 					echo "terminated with code ${EXIT_CODE}" >&2 | ||||
| 					;; | ||||
| 				( pretty ) | ||||
| 					echo "terminated with ${EXIT_COLOR}code ${EXIT_CODE}$(utils.colors.reset)" >&2 | ||||
| 					;; | ||||
| 				( json ) | ||||
| 					[[ ${EXIT_CODE} =~ 0 ]] \ | ||||
| 						&& echo.success --force-print "terminated with code ${EXIT_CODE}" \ | ||||
| 						|| echo.error   --force-print "terminated with code ${EXID_CODE}" \ | ||||
| 						; | ||||
| 					;; | ||||
| 			esac | ||||
| 		} | ||||
|  | ||||
| 		return ${EXIT_CODE} | ||||
| 	} | tee --append "${LOGFILE}" | ||||
| 		return $EXIT_CODE | ||||
| 	} 2>&1 | tee --append "$LOGFILE" | ||||
| } $@ | ||||
|  | ||||
| EXIT_CODE=$? | ||||
|  | ||||
| [ "${SCWRYPTS_TEMP_PATH}" ] && [ -d "${SCWRYPTS_TEMP_PATH}" ] \ | ||||
| 	&& { | ||||
| 		rm -- $(find "${SCWRYPTS_TEMP_PATH}" -mindepth 1 -maxdepth 1 -type f) | ||||
| 		rmdir "${SCWRYPTS_TEMP_PATH}" | ||||
| 	}	&>/dev/null | ||||
|  | ||||
| return ${EXIT_CODE} | ||||
|   | ||||
| @@ -1,223 +1,80 @@ | ||||
| # | ||||
| # typically you do not need to reload this plugin in a single session; | ||||
| # if for some reason you do, you can run the following command and | ||||
| # source this file again | ||||
| # | ||||
| # unset __SCWRYPTS_PLUGIN_LOADED | ||||
| # | ||||
| [[ $__SCWRYPTS_PLUGIN_LOADED =~ true ]] && return 0 | ||||
| ##################################################################### | ||||
| 
 | ||||
| command -v scwrypts &>/dev/null || { | ||||
| 	echo 'scwrypts is required in your PATH in order to use the zsh plugins; skipping' >&2 | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| NO_EXPORT_CONFIG=1 source "${0:a:h}/zsh/lib/import.driver.zsh" || return 42 | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| : \ | ||||
| 	&& command -v scwrypts &>/dev/null \ | ||||
| 	&& eval "$(scwrypts --config)" \ | ||||
| 	|| { | ||||
| 		echo 'scwrypts must be in PATH and properly configured; skipping zsh plugin setup' >&2 | ||||
| SCWRYPTS__ZSH_PLUGIN() { | ||||
| 	local SCWRYPT_SELECTION=$(scwrypts --list | FZF 'select a script' --header-lines 1) | ||||
| 	local NAME | ||||
| 	local TYPE | ||||
| 	local GROUP | ||||
| 	LBUFFER= RBUFFER= | ||||
| 	[ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; } | ||||
| 
 | ||||
| 	SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION | ||||
| 
 | ||||
| 	which scwrypts >/dev/null 2>&1\ | ||||
| 		&& RBUFFER="scwrypts" || RBUFFER="$SCWRYPTS_ROOT/scwrypts" | ||||
| 
 | ||||
| 	RBUFFER+=" --name $NAME --group $GROUP --type $TYPE" | ||||
| 	zle accept-line | ||||
| } | ||||
| 
 | ||||
| zle -N scwrypts SCWRYPTS__ZSH_PLUGIN | ||||
| bindkey $SCWRYPTS_SHORTCUT scwrypts | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| SCWRYPTS__ZSH_BUILDER_PLUGIN() { | ||||
| 	local SCWRYPT_SELECTION=$(scwrypts --list  | FZF 'select a script' --header-lines 1) | ||||
| 	echo $SCWRYPT_SELECTION >&2 | ||||
| 	local NAME | ||||
| 	local TYPE | ||||
| 	local GROUP | ||||
| 	LBUFFER= RBUFFER= | ||||
| 	[ ! $SCWRYPT_SELECTION ] && { zle accept-line; return 0; } | ||||
| 
 | ||||
| 	SCWRYPTS__SEPARATE_SCWRYPT_SELECTION $SCWRYPT_SELECTION | ||||
| 
 | ||||
| 	scwrypts -n --name $NAME --group $GROUP --type $TYPE -- --help >&2 || { | ||||
| 		zle accept-line | ||||
| 		return 0 | ||||
| 	} | ||||
| 	echo | ||||
| 
 | ||||
| __SCWRYPTS_PARSE() { | ||||
| 	SCWRYPT_SELECTION=$(scwrypts --list | fzf --ansi --prompt 'select a script : ' --header-lines 1) | ||||
| 	LBUFFER= RBUFFER= | ||||
| 	[ $SCWRYPT_SELECTION ] || return 1 | ||||
| 	zle reset-prompt | ||||
| 	which scwrypts >/dev/null 2>&1\ | ||||
| 		&& LBUFFER="scwrypts" || LBUFFER="$SCWRYPTS_ROOT/scwrypts" | ||||
| 
 | ||||
| 	NAME=$(echo "$SCWRYPT_SELECTION" | awk '{print $1;}') | ||||
| 	TYPE=$(echo "$SCWRYPT_SELECTION" | awk '{print $2;}') | ||||
| 	GROUP=$(echo "$SCWRYPT_SELECTION" | awk '{print $3;}') | ||||
| 
 | ||||
| 	[ $NAME ] && [ $TYPE ] && [ $GROUP ] | ||||
| 	LBUFFER+=" --name $NAME --group $GROUP --type $TYPE -- " | ||||
| } | ||||
| 
 | ||||
| zle -N scwrypts-builder SCWRYPTS__ZSH_BUILDER_PLUGIN | ||||
| bindkey $SCWRYPTS_BUILDER_SHORTCUT scwrypts-builder | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| [ $SCWRYPTS_SHORTCUT ] && { | ||||
| 	SCWRYPTS__ZSH_PLUGIN() { | ||||
| 		local SCWRYPT_SELECTION NAME TYPE GROUP | ||||
| 		__SCWRYPTS_PARSE || { zle accept-line; return 0; } | ||||
| SCWRYPTS__ZSH_PLUGIN_ENV() { | ||||
| 	local RESET='reset' | ||||
| 	local SELECTED=$(\ | ||||
| 		{ [ $SCWRYPTS_ENV ] && echo $RESET; SCWRYPTS__GET_ENV_NAMES; } \ | ||||
| 			| FZF 'select an environment' \ | ||||
| 	) | ||||
| 
 | ||||
| 		RBUFFER="scwrypts --name $NAME --type $TYPE --group $GROUP" | ||||
| 		zle accept-line | ||||
| 	zle clear-command-line | ||||
| 	[ $SELECTED ] && { | ||||
| 		[[ $SELECTED =~ ^$RESET$ ]] \ | ||||
| 			&& RBUFFER='unset SCWRYPTS_ENV' \ | ||||
| 			|| RBUFFER="export SCWRYPTS_ENV=$SELECTED" | ||||
| 	} | ||||
| 
 | ||||
| 	zle -N scwrypts SCWRYPTS__ZSH_PLUGIN | ||||
| 	bindkey $SCWRYPTS_SHORTCUT scwrypts | ||||
| 	unset SCWRYPTS_SHORTCUT | ||||
| 	zle accept-line | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| [ $SCWRYPTS_BUILDER_SHORTCUT ] && { | ||||
| 	SCWRYPTS__ZSH_BUILDER_PLUGIN() { | ||||
| 		local SCWRYPT_SELECTION NAME TYPE GROUP | ||||
| 		__SCWRYPTS_PARSE || { echo >&2; zle accept-line; return 0; } | ||||
| 		echo $SCWRYPT_SELECTION >&2 | ||||
| 
 | ||||
| 		scwrypts -n --name $NAME --group $GROUP --type $TYPE -- --help >&2 || { | ||||
| 			zle accept-line | ||||
| 			return 0 | ||||
| 		} | ||||
| 		echo | ||||
| 
 | ||||
| 		zle reset-prompt | ||||
| 		LBUFFER="scwrypts --name $NAME --type $TYPE --group $GROUP -- " | ||||
| 	} | ||||
| 
 | ||||
| 	zle -N scwrypts-builder SCWRYPTS__ZSH_BUILDER_PLUGIN | ||||
| 	bindkey $SCWRYPTS_BUILDER_SHORTCUT scwrypts-builder | ||||
| 	unset SCWRYPTS_BUILDER_SHORTCUT | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| [ $SCWRYPTS_ENV_SHORTCUT ] && { | ||||
| 	SCWRYPTS__ZSH_PLUGIN_ENV() { | ||||
| 		local RESET='reset' | ||||
| 		local SELECTED=$(\ | ||||
| 			{ [ $SCWRYPTS_ENV ] && echo $RESET; scwrypts --list-envs; } \ | ||||
| 				| fzf --prompt 'select an environment : ' \ | ||||
| 		) | ||||
| 
 | ||||
| 		zle clear-command-line | ||||
| 		[ $SELECTED ] && { | ||||
| 			[[ $SELECTED =~ ^$RESET$ ]] \ | ||||
| 				&& RBUFFER='unset SCWRYPTS_ENV' \ | ||||
| 				|| RBUFFER="export SCWRYPTS_ENV=$SELECTED" | ||||
| 		} | ||||
| 		zle accept-line | ||||
| 	} | ||||
| 
 | ||||
| 	zle -N scwrypts-setenv SCWRYPTS__ZSH_PLUGIN_ENV | ||||
| 	bindkey $SCWRYPTS_ENV_SHORTCUT scwrypts-setenv | ||||
| 	unset SCWRYPTS_ENV_SHORTCUT | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| # badass(/terrifying?) zsh autocompletion | ||||
| command -v compdef &>/dev/null && { | ||||
| 	_scwrypts() { | ||||
| 		echo $words | grep -q "\s--\s" && _arguments && return 0 | ||||
| 		eval "_arguments $( | ||||
| 			{ | ||||
| 			HELP=$(scwrypts --help 2>&1 | sed -n 's/^\s\+\(-.*   .\)/\1/p' | sed 's/[[]/(/g; s/[]]/)/g') | ||||
| 			echo $HELP \ | ||||
| 				| sed 's/^\(\(-[^-\s]\),*\s*\|\)\(\(--[-a-z0-9A-Z\]*\)\s\(<\([^>]*\)>\|\)\|\)\s\+\(.*\)/\2[\7]:\6:->\2/' \ | ||||
| 				| grep -v '^[[]' \ | ||||
| 				; | ||||
| 
 | ||||
| 			echo $HELP \ | ||||
| 				| sed 's/^\(\(-[^-\s]\),*\s*\|\)\(\(--[-a-z0-9A-Z\]*\)\s\(<\([^>]*\)>\|\)\|\)\s\+\(.*\)/\4[\7]:\6:->\4/' \ | ||||
| 				| grep -v '^[[]' \ | ||||
| 				; | ||||
| 
 | ||||
| 			echo ":pattern:->pattern" | ||||
| 			echo ":pattern:->pattern" | ||||
| 			echo ":pattern:->pattern" | ||||
| 			echo ":pattern:->pattern" | ||||
| 			echo ":pattern:->pattern" | ||||
| 
 | ||||
| 			} | sed 's/::->.*$//g' | sed "s/\\(^\\|$\\)/'/g" | tr '\n' ' ' | ||||
| 		)" | ||||
| 
 | ||||
| 		local _group='' | ||||
| 		echo $words | grep -q ' -g [^\s]' \ | ||||
| 			&& _group=$(echo $words | sed 's/.*-g \([^ 	]\+\)\s*.*/\1/') | ||||
| 		echo $words | grep -q ' --group .' \ | ||||
| 			&& _group=$(echo $words | sed 's/.*--group \([^ 	]\+\)\s*.*/\1/') | ||||
| 
 | ||||
| 		local _type='' | ||||
| 		echo $words | grep -q ' -t [^\s]' \ | ||||
| 			&& _type=$(echo $words | sed 's/.*-t \([^ 	]\+\)\s*.*/\1/') | ||||
| 		echo $words | grep -q ' --type .' \ | ||||
| 			&& _type=$(echo $words | sed 's/.*--type \([^ 	]\+\)\s*.*/\1/') | ||||
| 
 | ||||
| 		local _name='' | ||||
| 		echo $words | grep -q ' -m [^\s]' \ | ||||
| 			&& _name=$(echo $words | sed 's/.*-m \([^ 	]\+\)\s*.*/\1/') | ||||
| 		echo $words | grep -q ' --name .' \ | ||||
| 			&& _name=$(echo $words | sed 's/.*--name \([^ 	]\+\)\s*.*/\1/') | ||||
| 
 | ||||
| 		local _pattern _patterns=() | ||||
| 		[ ! $_name ] \ | ||||
| 			&& _patterns=($(echo "${words[@]:1}" | sed 's/\s\+/\n/g' | grep -v '^-')) | ||||
| 
 | ||||
| 		_get_remaining_scwrypts() { | ||||
| 			[ $_name  ] || local  _name='[^ 	]\+' | ||||
| 			[ $_type  ] || local  _type='[^ 	]\+' | ||||
| 			[ $_group ] || local _group='[^ 	]\+' | ||||
| 
 | ||||
| 			local remaining=$(\ | ||||
| 				scwrypts --list \ | ||||
| 					| sed "1d; s,\x1B\[[0-9;]*[a-zA-Z],,g" \ | ||||
| 					| grep "^$_name\s" \ | ||||
| 					| grep "\s$_group$" \ | ||||
| 					| grep "\s$_type\s" \ | ||||
| 				) | ||||
| 
 | ||||
| 			for _pattern in ${_patterns[@]} | ||||
| 			do | ||||
| 				remaining=$(echo "$remaining" | grep "$_pattern") | ||||
| 			done | ||||
| 
 | ||||
| 			echo "$remaining" | ||||
| 		} | ||||
| 
 | ||||
| 		case $state in | ||||
| 			( -m | --name ) | ||||
| 				compadd $(_get_remaining_scwrypts | awk '{print $1;}' | sort -u) | ||||
| 				;; | ||||
| 
 | ||||
| 			( -t | --type ) | ||||
| 				compadd $(_get_remaining_scwrypts | awk '{print $2;}' | sort -u) | ||||
| 				;; | ||||
| 
 | ||||
| 			( -g | --group ) | ||||
| 				[[ $_name$_type$_group =~ ^$ ]] \ | ||||
| 					&& compadd $(scwrypts --list-groups) \ | ||||
| 					|| compadd $(_get_remaining_scwrypts | awk '{print $3;}' | sort -u) \ | ||||
| 				;; | ||||
| 
 | ||||
| 			( -e | --env ) | ||||
| 				compadd $(scwrypts --list-envs) | ||||
| 				;; | ||||
| 
 | ||||
| 			( -v | --log-level ) | ||||
| 				local _help="$(\ | ||||
| 					scwrypts --help 2>&1 \ | ||||
| 						| sed -n '/-v, --log-level/,/^$/p' \ | ||||
| 						| sed -n 's/\s\+\([0-9]\) : \(.*\)/\1 -- \2/p' \ | ||||
| 				)" | ||||
| 
 | ||||
| 				eval "local _descriptions=($(echo "$_help" | sed "s/\\(^\|$\\)/'/g"))" | ||||
| 				local _values=($(echo "$_help" | sed 's/ --.*//')) | ||||
| 				compadd -d _descriptions -a _values | ||||
| 				;; | ||||
| 
 | ||||
| 			( -o | --output ) | ||||
| 				compadd pretty json | ||||
| 				;; | ||||
| 
 | ||||
| 			( pattern ) | ||||
| 				[[ $_name =~ ^$ ]] && { | ||||
| 					local _remaining_scwrypts="$(_get_remaining_scwrypts)" | ||||
| 					# stop providing suggestions if your pattern is sufficient | ||||
| 					[[ $(echo $_remaining_scwrypts | wc -l) -le 1 ]] && return 0 | ||||
| 
 | ||||
| 					local _remaining_patterns="$(echo "$_remaining_scwrypts" | sed 's/\s\+/\n/g; s|/|\n|g; s/-/\n/g;' | sort -u)" | ||||
| 
 | ||||
| 					for _pattern in ${_patterns[@]} | ||||
| 					do | ||||
| 						_remaining_patterns="$(echo "$_remaining_patterns" | grep -v "^$_pattern$")" | ||||
| 					done | ||||
| 					compadd $(echo $_remaining_patterns) | ||||
| 				} | ||||
| 				;; | ||||
| 
 | ||||
| 			( * ) ;; | ||||
| 		esac | ||||
| 	} | ||||
| 	compdef _scwrypts scwrypts | ||||
| } | ||||
| 
 | ||||
| __SCWRYPTS_PLUGIN_LOADED=true | ||||
| zle -N scwrypts-setenv SCWRYPTS__ZSH_PLUGIN_ENV | ||||
| bindkey $SCWRYPTS_ENV_SHORTCUT scwrypts-setenv | ||||
|   | ||||
| @@ -1,177 +0,0 @@ | ||||
| # | ||||
| # configuration for a scwrypts "group" or "plugin" | ||||
| # | ||||
| 
 | ||||
| # this file defines the configuration for the 'scwrypts' group which | ||||
| # is required for proper operation, but otherwise loads exactly like | ||||
| # any other group/plugin | ||||
| 
 | ||||
| # | ||||
| # both ${scwryptsgroup} and ${scwryptsgrouproot} are set automatically | ||||
| # | ||||
| # ${scwryptsgroup} is determined by the filename 'NAME.scwrypts.zsh' | ||||
| # | ||||
| # NAME must be unique and match : ^[a-z][a-z0-9_]*[a-z0-9]$ | ||||
| #  - STARTS with a lower letter | ||||
| #  - ENDS   with a lower letter or number | ||||
| #  - contains only lower-alphanumeric and underscores | ||||
| #  - is at least two characters long | ||||
| # | ||||
| # ${scwryptsgrouproot} is automatically set as the parent directory | ||||
| # /path/to/group-source           <-- this will be ${scwryptsgrouproot} | ||||
| #   ├── groupname.scwrypts.zsh | ||||
| #   └── your-scwrypts-source-here | ||||
| # | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### REQUIRED CONFIGURATION ########################################## | ||||
| ##################################################################### | ||||
| 
 | ||||
| # Currently, no configuration is required; simply creating the | ||||
| # groupname.scwrypts.zsh is sufficient to define a new group | ||||
| 
 | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### OPTIONAL CONFIGURATION ########################################## | ||||
| ##################################################################### | ||||
| 
 | ||||
| # ${scwryptsgroup}__option_key configuration values can be accessed anywhere in zsh scwrypts | ||||
| # with $(scwrypts.config.group group-name option_key) | ||||
| 
 | ||||
| readonly ${scwryptsgroup}__type= | ||||
| # | ||||
| # ${scwryptsgroup}__type (optional) (default = not set) | ||||
| # | ||||
| # used when only one scwrypt "type" (e.g. 'zsh' or 'py') is declared | ||||
| # in the group | ||||
| # | ||||
| # WHEN THIS IS SET, scwrypts will lookup executables starting from the | ||||
| # base directory (using type ${scwryptsgroup}__type): | ||||
| # | ||||
| # /path/to/group-source | ||||
| #   ├── groupname.scwrypts.zsh | ||||
| #   ├── valid-scwrypts-executable | ||||
| #   └── some-other | ||||
| #       ├── valid-scwrypts-executable | ||||
| #       └── etc | ||||
| # | ||||
| # when this is NOT set, scwrypts must be nested inside a directory | ||||
| # which matches the type name | ||||
| # | ||||
| # /path/to/group-source | ||||
| #   ├── groupname.scwrypts.zsh | ||||
| #   │ | ||||
| #   ├── zsh | ||||
| #   │   ├── valid-scwrypts-executable | ||||
| #   │   └── some-other | ||||
| #   │       ├── valid-scwrypts-executable | ||||
| #   │       └── etc | ||||
| #   │ | ||||
| #   └── py | ||||
| #       ├── valid-scwrypts-executable.py | ||||
| #       └── some-other | ||||
| #           ├── valid-scwrypts-executable.py | ||||
| #           └── etc | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| readonly ${scwryptsgroup}__color=$(utils.colors.green) | ||||
| # | ||||
| # ${scwryptsgroup}__color (optional) (default = no color / regular text color) | ||||
| # | ||||
| # an ANSI color sequence which determines the color of scwrypts in | ||||
| # interactive menus | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| readonly ${scwryptsgroup}__zshlibrary= | ||||
| # | ||||
| # ${scwryptsgroup}__zshlibrary (optional) (default = *see below*) | ||||
| # | ||||
| # allows arbitrary 'use module/name --group groupname' imports | ||||
| # within zsh-type scwrypts | ||||
| # | ||||
| # usually this is set at or within ${scwryptsgrouproot} | ||||
| # | ||||
| # by default, this uses either: | ||||
| #  1. ${scwryptsgrouproot}/zsh/lib (compatibility) | ||||
| #  2. ${scwryptsgrouproot}/zsh     (preferred) | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| readonly ${scwryptsgroup}__virtualenv_path="${SCWRYPTS_STATE_PATH}/virtualenv" | ||||
| # | ||||
| # ${scwryptsgroup}__virtualenv_path | ||||
| #   (optional) | ||||
| #   (default = ~/.local/state/scwrypts/virtualenv) | ||||
| # | ||||
| # defines the path in which virtual environments are stored for | ||||
| # the group | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| readonly ${scwryptsgroup}__required_environment_regex= | ||||
| # | ||||
| # ${scwryptsgroup}__required_environment_regex (optional) (default = allow any) | ||||
| # | ||||
| # helps isolate environment by locking group execution to | ||||
| # environment names which match the regex | ||||
| # | ||||
| # when not set, no environment name restrictions are enforced | ||||
| # | ||||
| # when set, interactive menus will be adjusted and non-interactive | ||||
| # execution will fail if the name of the environment does not match | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### ADVANCED CONFIGURATION ########################################## | ||||
| ##################################################################### | ||||
| 
 | ||||
| #${scwryptsgroup}.list-available() {} | ||||
| # | ||||
| # ${scwryptsgroup}.list-available() | ||||
| # | ||||
| # a function which outputs lines of "${SCWRYPT_TYPE}/${SCWRYPT_NAME}" | ||||
| # to stdout | ||||
| # | ||||
| # by default, looks for executable files in ${scwryptsgrouproot} | ||||
| # | ||||
| # during execution of this function, the following variables are | ||||
| # available: | ||||
| # | ||||
| # - $GROUP_ROOT : USE THIS instead of ${scwryptsgrouproot} | ||||
| # - $GROUP_TYPE : USE THIS instead of ${scwryptsgroup}__type | ||||
| # | ||||
| # (see ./zsh/scwrypts/list-available.module.zsh for more details) | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| #${scwryptsgroup}.TYPE.get-runstring() {} | ||||
| # | ||||
| # a function which outputs what should be literally run when executing | ||||
| # the indicated type; scwrypts already implements runstring generators | ||||
| # for supported types (that's the main thing which makes them "supported") | ||||
| # | ||||
| # configuration variables are still automatically included as a | ||||
| # prefix to the runstring | ||||
| # | ||||
| # (see ./zsh/scwrypts/get-runstring.module.zsh for more details) | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### HYPER-ADVANCED CONFIGURATION #################################### | ||||
| ##################################################################### | ||||
| 
 | ||||
| # | ||||
| # additional zsh can be defined or run arbitrarily; this is NOT recommended | ||||
| # unless you understand the implications of the various places where | ||||
| # this code is loaded | ||||
| # | ||||
| # if you want to know where to get started (it will take some learning!), | ||||
| # review the execution process in: | ||||
| #   - ./scwrypts | ||||
| #   - ./zsh/scwrypts/get-runstring.module.zsh | ||||
| #   - ./zsh/scwrypts/environment/user.module.zsh | ||||
| # | ||||
							
								
								
									
										112
									
								
								zsh/README.md
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								zsh/README.md
									
									
									
									
									
								
							| @@ -1,113 +1,21 @@ | ||||
| # ZSH Scwrypts | ||||
| [](https://1password.com/downloads/command-line) | ||||
| [](https://github.com/BurntSushi/ripgrep) | ||||
| [](https://github.com/dbcli/pgcli) | ||||
| [](https://github.com/junegunn/fzf) | ||||
| [](https://github.com/mikefarah/yq) | ||||
| [](https://github.com/stedolan/jq) | ||||
| [](https://github.com/dbcli/pgcli) | ||||
| <br> | ||||
|  | ||||
| Since they emulate direct user interaction, shell scripts are a (commonly dreaded) go-to for automation. | ||||
| Since they emulate direct user interaction, shell scripts are often the straightforward choice for task automation. | ||||
|  | ||||
| Although the malleability of shell scripts can make integrations quickly, the ZSH-type scwrypt provides a structure to promote extendability and clean code while performing a lot of the heavy lifting to ensure consistent execution across different runtimes. | ||||
| ## Basic Utilities | ||||
|  | ||||
| ## The Basic Framework | ||||
| One of my biggest pet-peeves with scripting is when every line of a *(insert-language-here)* program is escaped to shell. | ||||
| This kind of program, which doesn't use language features, should be a shell script. | ||||
| While there are definitely unavoidable limitations to shell scripting, we can minimize a variety of problems with a modern shell and shared utilities library. | ||||
|  | ||||
| Take a look at the simplest ZSH-type scwrypt: [hello-world](./hello-world). | ||||
| The bare minimum API for ZSH-type scwrypts is to: | ||||
|  | ||||
| 1. include the shebang `#!/usr/bin/env zsh` on the first line of the file | ||||
| 2. wrap your zsh in a function called `MAIN()` | ||||
| 3. make the file executable (e.g. `chmod +x hello-world`) | ||||
|  | ||||
| Once this is complete, you are free to simply _write valid zsh_ then execute the scwrypt with `scwrypts hello world zsh`! | ||||
|  | ||||
| ## Basics+ | ||||
|  | ||||
| While it would be perfectly fine to use the `echo` function in our scwrypt, you'll notice that the `hello-world` scwrypt instead uses `echo.success` which is _not_ valid ZSH by default. | ||||
| This is a helper function provided by the scwrypts ZSH library, and it does a lot more work than you'd expect. | ||||
|  | ||||
| Although this function defaults to print user messages in color, notice what happens when you run `scwrypts --output json hello world zsh`: | ||||
|  | ||||
| ```json | ||||
| {"timestamp":1745674060,"runtime":"c62737da-481e-4013-a370-4dedc76bf4d2","scwrypt":"start of hello-world scwrypts zsh","logLevel":"3","subscwrypt":0} | ||||
| {"timestamp":1745674060,"runtime":"c62737da-481e-4013-a370-4dedc76bf4d2","status":"SUCCESS","message":"\"Hello, World!\""} | ||||
| {"timestamp":1745674060,"runtime":"c62737da-481e-4013-a370-4dedc76bf4d2","status":"SUCCESS","message":"\"terminated with code 0\""} | ||||
| ``` | ||||
|  | ||||
| We get a LOT more information. | ||||
|  | ||||
| It's 100% possible for you to include your own take on printing messages, but it is highly recommended to use the tools provided here. | ||||
|  | ||||
| ### What is loaded by default? | ||||
|  | ||||
| By default, every ZSH-type scwrypt will load [the basic utilities suite](./utils), which is a little different from scwrypts ZSH modules, and a little bit complex. | ||||
| Although it's totally worth a deep-dive, here are the fundamentals you should ALWAYS use: | ||||
|  | ||||
| #### Printing User Messages or Logs | ||||
|  | ||||
| Whenever you want to print a message to the user or logs, rather than using `echo`, use the following: | ||||
| <!------------------------------------------------------------------------> | ||||
| | function name   | minimum log level | description                       | | ||||
| | --------------- | ----------------- | --------------------------------- | | ||||
| | `echo.success`  |                 1 | indicate successful completion    | | ||||
| | `echo.error`    |                 1 | indicate an error has occurred    | | ||||
| | `echo.reminder` |                 1 | an important, information message | | ||||
| | `echo.status`   |                 2 | a regular, information message    | | ||||
| | `echo.warning`  |                 3 | a non-critical warning            | | ||||
| | `echo.debug`    |                 4 | a message for scwrypt developers  | | ||||
| <!------------------------------------------------------------------------> | ||||
|  | ||||
| Of the `echo` family, there are two unique functions: | ||||
|  | ||||
| - `echo.error` will **increment the `ERRORS` variable** then return an error code of `$ERRORS` (this makes it easy to chain with command failure by using `||`) | ||||
| - `echo.debug` will inject state information like the timestamp and current function stack | ||||
|  | ||||
|  | ||||
| #### Yes / No Prompts | ||||
|  | ||||
| The two helpers `utils.Yn` and `utils.yN` take a user-friendly yes/no question as an argument. | ||||
|  | ||||
| - when the user responds "yes", the command returns 0 / success / `&&` | ||||
| - when the user responds "no", the command returns 1 / error / `||` | ||||
| - when the user responds with _nothing_ (e.g. just presses enter), the _default_ is used | ||||
|  | ||||
| The two commands work identically; however, the capitalization denotes the default: | ||||
| - `utils.Yn` = default "yes" | ||||
| - `utils.yN` = default "no" | ||||
|  | ||||
| #### Select from a List Prompt | ||||
|  | ||||
| When you want the user to select an item from a list, scwrypts typically use `fzf`. | ||||
| There are a LOT of options to `fzf`, so there are two provided helpers. | ||||
|  | ||||
| The basic selector, `utils.fzf` (most of the time, you want to use this one) which outputs: | ||||
| - _the selection_ if the user made a choice | ||||
| - _nothing / empty string_ if the user cancelled or made an invalid choice | ||||
|  | ||||
| The user-input selector, `utils.fzf.user-input` which outputs: | ||||
| - _the selection_ if the user made a choice | ||||
| - _the text typed by the user_ if the user typed something other than the listed choices | ||||
| - _nothing / empty string_ if the user cancelled | ||||
| - _a secondary `utils.fzf` prompt_ if the user's choice was ambiguous | ||||
|  | ||||
| ### Imports | ||||
|  | ||||
| Don't use `source` in ZSH-type scwrypts (I mean, if you're pretty clever you can get it to work, but DON'T THOUGH). | ||||
| Instead, use `use`! | ||||
|  | ||||
| The `use` command, rather than specifying file directories, you reference the path to `*.module.zsh`. | ||||
| This means you don't have to know the exact path to any given file. | ||||
| For example, if I wanted to import the safety tool for `aws` CLI commands, I can do the following: | ||||
|  | ||||
| ```zsh | ||||
| #!/usr/bin/env zsh | ||||
|  | ||||
| use cloud/aws | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
|     cloud.aws sts get-caller-identity | ||||
| } | ||||
| ``` | ||||
| Loaded by `common.zsh`, the [`utils/` library](./utils) provides: | ||||
| - common function wrappers to unify flags and context | ||||
| - lazy dependency and environment variable validation | ||||
| - consistent (and pretty) user input / output | ||||
|   | ||||
| @@ -1,13 +0,0 @@ | ||||
| # | ||||
| # provides utilities for interacting with Amazon Web Services (AWS) | ||||
| # | ||||
| 
 | ||||
| # context wrapper for AWS CLI v2 | ||||
| use cloud/aws/cli | ||||
| eval "${scwryptsmodule}() { ${scwryptsmodule}.cli \$@; }" | ||||
| 
 | ||||
| # simplify context commands for kubectl on EKS | ||||
| use cloud/aws/eks | ||||
| 
 | ||||
| # context wrapper for eksctl | ||||
| use cloud/aws/eksctl | ||||
| @@ -1,28 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.provides-aws-cli() { | ||||
| 	unittest.test.provides ${testmodule}.cli | ||||
| } | ||||
| 
 | ||||
| test.provides-aws-cli-alias() { | ||||
| 	unittest.test.provides ${testmodule} | ||||
| } | ||||
| 
 | ||||
| test.provides-eks() { | ||||
| 	unittest.test.provides ${testmodule}.eks | ||||
| } | ||||
| 
 | ||||
| test.provides-eksctl() { | ||||
| 	unittest.test.provides ${testmodule}.eksctl | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| DEPENDENCIES+=(aws) | ||||
| 
 | ||||
| use cloud/aws/zshparse | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSERS=(cloud.aws.zshparse.overrides) | ||||
| 	local ARGS=() | ||||
| 	local DESCRIPTION=" | ||||
| 		Safe context wrapper for aws cli commands; prevents accidental local environment | ||||
| 		bleed-through, but otherwise works exactly like 'aws'. For help with awscli, try | ||||
| 		'AWS [command] help' (no -h or --help) | ||||
| 
 | ||||
| 		This wrapper should be used in place of _all_ 'aws' usages within scwrypts. | ||||
| 		" | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	echo.debug "invoking '$(echo "$AWS_EVAL_PREFIX" | sed 's/AWS_\(ACCESS_KEY_ID\|SECRET_ACCESS_KEY\)=[^ ]\+ //g')aws ${AWS_CONTEXT_ARGS[@]} ${ARGS[@]}'" | ||||
| 	eval "${AWS_EVAL_PREFIX}aws ${AWS_CONTEXT_ARGS[@]} ${ARGS[@]}" | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { | ||||
| 	return 0  # uses default args parser | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.usage() { | ||||
| 	USAGE__args+='\$@   arguments forwarded to the AWS CLI' | ||||
| } | ||||
| @@ -1,65 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.cli | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/cli | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock aws | ||||
| 	unittest.mock echo.debug | ||||
| 
 | ||||
| 	_ARGS=($(uuidgen) $(uuidgen) $(uuidgen)) | ||||
| 
 | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 	_AWS_PROFILE=$(uuidgen) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value $(uuidgen) | ||||
| 	unittest.mock.env AWS_PROFILE --value ${_AWS_PROFILE} | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset _AWS_REGION | ||||
| 	unset _AWS_PROFILE | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.forwards-arguments() { | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	aws.assert.callstack \ | ||||
| 		--output json \ | ||||
| 		--region ${_AWS_REGION} \ | ||||
| 		--profile ${_AWS_PROFILE} \ | ||||
| 		${_ARGS[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.overrides-region() { | ||||
| 	local OVERRIDE_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	${testmodule} --region ${OVERRIDE_REGION} ${_ARGS[@]} | ||||
| 
 | ||||
| 	aws.assert.callstack \ | ||||
| 		--output json \ | ||||
| 		--region ${OVERRIDE_REGION} \ | ||||
| 		--profile ${_AWS_PROFILE} \ | ||||
| 		${_ARGS[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.overrides-account() { | ||||
| 	local OVERRIDE_ACCOUNT=$(uuidgen) | ||||
| 
 | ||||
| 	${testmodule} --account ${OVERRIDE_ACCOUNT} ${_ARGS[@]} | ||||
| 
 | ||||
| 	echo.debug.assert.callstackincludes \ | ||||
| 		AWS_ACCOUNT=${OVERRIDE_ACCOUNT} \ | ||||
| 		; | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| # | ||||
| # common operations for AWS Elastic Container Registry (ECR) | ||||
| # | ||||
| 
 | ||||
| # that obnoxious command which pushes the AWS temporary credentials to 'docker login' | ||||
| use cloud/aws/ecr/login | ||||
| @@ -1,16 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.ecr | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/ecr | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.provides-ecr-login() { | ||||
| 	unittest.test.provides ${testmodule}.login | ||||
| } | ||||
| @@ -1,17 +1,7 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use cloud/aws/ecr | ||||
| ##################################################################### | ||||
|  | ||||
| use cloud/aws/ecr/login | ||||
| use cloud/aws/zshparse | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| USAGE__description=' | ||||
| 	interactively setup temporary credentials for ECR in the given region | ||||
| ' | ||||
|  | ||||
| cloud.aws.zshparse.overrides.usage | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { cloud.aws.ecr.login $@; } | ||||
| MAIN() { | ||||
| 	ECR_LOGIN $@ | ||||
| } | ||||
|   | ||||
| @@ -1,30 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/cli | ||||
| use cloud/aws/zshparse | ||||
| 
 | ||||
| DEPENDENCIES+=(docker) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local DESCRIPTION=" | ||||
| 		Performs the appropriate 'docker login' command with temporary | ||||
| 		credentials from AWS. | ||||
| 	" | ||||
| 
 | ||||
| 	local PARSERS=(cloud.aws.zshparse.overrides) | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	${AWS} ecr get-login-password \ | ||||
| 		| docker login "${ACCOUNT}.dkr.ecr.${REGION}.amazonaws.com" \ | ||||
| 			--username AWS \ | ||||
| 			--password-stdin \ | ||||
| 			&>/dev/null \ | ||||
| 		&& echo.success "authenticated docker for '${ACCOUNT}' in '${REGION}'" \ | ||||
| 		|| echo.error "unable to authenticate docker for '${ACCOUNT}' in '${REGION}'" \ | ||||
| 		; | ||||
| } | ||||
| @@ -1,47 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.ecr.login | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/ecr/login | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock cloud.aws.cli | ||||
| 	unittest.mock docker | ||||
| 
 | ||||
| 	_AWS_ACCOUNT=$(uuidgen) | ||||
| 	_AWS_PROFILE=$(uuidgen) | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value ${_AWS_ACCOUNT} | ||||
| 	unittest.mock.env AWS_PROFILE --value ${_AWS_PROFILE} | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| 
 | ||||
| 	_EXPECTED_AWS_ARGS=( | ||||
| 		--account ${_AWS_ACCOUNT} | ||||
| 		--region  ${_AWS_REGION} | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset \ | ||||
| 		_AWS_ACCOUNT _AWS_PROFILE _AWS_REGION \ | ||||
| 		_EXPECTED_AWS_ARGS \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.login-forwards-credentials-to-docker() { | ||||
| 	${testmodule} | ||||
| 
 | ||||
| 	docker.assert.callstack \ | ||||
| 		login "${_AWS_ACCOUNT}.dkr.ecr.${_AWS_REGION}.amazonaws.com" \ | ||||
| 			--username AWS \ | ||||
| 			--password-stdin \ | ||||
| 			; | ||||
| } | ||||
| @@ -1,82 +1,64 @@ | ||||
| #!/usr/bin/env zsh | ||||
| ##################################################################### | ||||
|  | ||||
| use cloud/aws/cli | ||||
| use cloud/aws/zshparse/overrides | ||||
|  | ||||
| DEPENDENCIES+=(jq mount sort sudo) | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(jq) | ||||
| REQUIRED_ENV+=(AWS__EFS__LOCAL_MOUNT_POINT) | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| USAGE__description=' | ||||
| 	interactively mount an AWS EFS volume to the local filesystem | ||||
| ' | ||||
|  | ||||
| use cloud/aws/cli | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	local PARSERS=(cloud.aws.zshparse.overrides) | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 	utils.io.getsudo || return 1 | ||||
| 	########################################## | ||||
|  | ||||
| 	{ | ||||
| 		mkdir -p -- "${AWS__EFS__LOCAL_MOUNT_POINT}" \ | ||||
| 			|| sudo mkdir -p -- "${AWS__EFS__LOCAL_MOUNT_POINT}" | ||||
| 	} &>/dev/null | ||||
|  | ||||
| 	[ -d "${AWS__EFS__LOCAL_MOUNT_POINT}" ] \ | ||||
| 		|| echo.error "unable to create local mount point '${AWS__EFS__LOCAL_MOUNT_POINT}'" \ | ||||
| 		|| return | ||||
|  | ||||
| 	local FS_ID=$(\ | ||||
| 		$AWS efs describe-file-systems \ | ||||
| 			| jq -r '.[] | .[] | .FileSystemId' \ | ||||
| 			| utils.fzf 'select a filesystem to mount' \ | ||||
| 	) | ||||
| 	[ ! ${FS_ID} ] && utils.abort | ||||
|  | ||||
| 	local MOUNT_POINT="${AWS__EFS__LOCAL_MOUNT_POINT}/${FS_ID}" | ||||
| 	[ -d "${MOUNT_POINT}" ] && sudo rmdir "${MOUNT_POINT}" &>/dev/null | ||||
| 	[ -d "${MOUNT_POINT}" ] && { | ||||
| 		echo.status "${FS_ID} is already mounted" | ||||
| 		return 0 | ||||
| 	GETSUDO || exit 1 | ||||
| 	[ ! -d $AWS__EFS__LOCAL_MOUNT_POINT ] && { | ||||
| 		sudo mkdir $AWS__EFS__LOCAL_MOUNT_POINT \ | ||||
| 			&& STATUS "created local mount point '$AWS__EFS__LOCAL_MOUNT_POINT'" | ||||
| 	} | ||||
|  | ||||
| 	local MOUNT_TARGETS=$($AWS efs describe-mount-targets --file-system-id ${FS_ID}) | ||||
| 	local ZONE=$(\ | ||||
| 		echo ${MOUNT_TARGETS} \ | ||||
| 			| jq -r '.[] | .[] | .AvailabilityZoneName' \ | ||||
| 			| sort -u | utils.fzf 'select availability zone'\ | ||||
| 	local FS_ID=$(\ | ||||
| 		AWS efs describe-file-systems \ | ||||
| 		| jq -r '.[] | .[] | .FileSystemId' \ | ||||
| 		| FZF 'select a filesystem to mount' \ | ||||
| 	) | ||||
| 	[ ! "${ZONE}" ] && utils.abort | ||||
| 	[ ! $FS_ID ] && ABORT | ||||
|  | ||||
| 	local MOUNT_POINT="$AWS__EFS__LOCAL_MOUNT_POINT/$FS_ID" | ||||
| 	[ -d "$MOUNT_POINT" ] && sudo rmdir "$MOUNT_POINT" >/dev/null 2>&1 | ||||
| 	[ -d "$MOUNT_POINT" ] && { | ||||
| 		STATUS "$FS_ID is already mounted" | ||||
| 		exit 0 | ||||
| 	} | ||||
|  | ||||
| 	local MOUNT_TARGETS=$(AWS efs describe-mount-targets --file-system-id $FS_ID) | ||||
| 	local ZONE=$(\ | ||||
| 		echo $MOUNT_TARGETS \ | ||||
| 		| jq -r '.[] | .[] | .AvailabilityZoneName' \ | ||||
| 		| sort -u | FZF 'select availability zone'\ | ||||
| 	) | ||||
| 	[ ! $ZONE ] && ABORT | ||||
|  | ||||
| 	local MOUNT_IP=$(\ | ||||
| 		echo ${MOUNT_TARGETS} \ | ||||
| 			| jq -r ".[] | .[] | select (.AvailabilityZoneName == \"${ZONE}\") | .IpAddress" \ | ||||
| 			| head -n1 \ | ||||
| 		echo $MOUNT_TARGETS \ | ||||
| 		| jq -r ".[] | .[] | select (.AvailabilityZoneName == \"$ZONE\") | .IpAddress" \ | ||||
| 		| head -n1 \ | ||||
| 	) | ||||
|  | ||||
| 	echo.success  'ready to mount!' | ||||
| 	echo.status " | ||||
| 		file system id    : ${FS_ID} | ||||
| 		availability zone : ${ZONE} | ||||
| 		file system ip    : ${MOUNT_IP} | ||||
| 		local mount point : ${MOUNT_POINT} | ||||
| 	 " | ||||
| 	echo.reminder 'for private file-systems, you must be connected to the appropriate VPN' | ||||
| 	Yn 'proceed?' || utils.abort | ||||
| 	SUCCESS 'ready to mount!' | ||||
| 	REMINDER 'for private file-systems, you must be connected to the appropriate VPN' | ||||
|  | ||||
| 	sudo mkdir -- "${MOUNT_POINT}" \ | ||||
| 	STATUS "file system id    : $FS_ID" | ||||
| 	STATUS "availability zone : $ZONE" | ||||
| 	STATUS "file system ip    : $MOUNT_IP" | ||||
| 	STATUS "local mount point : $MOUNT_POINT" | ||||
|  | ||||
| 	Yn 'proceed?' || ABORT | ||||
|  | ||||
| 	sudo mkdir $MOUNT_POINT \ | ||||
| 		&& sudo mount \ | ||||
| 			-t nfs4 \ | ||||
| 			-o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport \ | ||||
| 			"${MOUNT_IP}:/" \ | ||||
| 			"${MOUNT_POINT}" \ | ||||
| 		&& echo.success "mounted at '${MOUNT_POINT}'" \ | ||||
| 			$MOUNT_IP:/ \ | ||||
| 			"$MOUNT_POINT" \ | ||||
| 		&& SUCCESS "mounted at '$MOUNT_POINT'" \ | ||||
| 		|| { | ||||
| 			sudo rmdir -- "${MOUNT_POINT}" &>/dev/null | ||||
| 			echo.error "unable to mount '${FS_ID}'" | ||||
| 		} | ||||
| 		sudo rmdir $MOUNT_POINT >/dev/null 2>&1 | ||||
| 		FAIL 2 "unable to mount '$FS_ID'" | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,39 +1,32 @@ | ||||
| #!/usr/bin/env zsh | ||||
| ##################################################################### | ||||
|  | ||||
| DEPENDENCIES+=(jq umount sudo) | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(jq) | ||||
| REQUIRED_ENV+=(AWS__EFS__LOCAL_MOUNT_POINT) | ||||
|  | ||||
| use cloud/aws/cli | ||||
| ##################################################################### | ||||
|  | ||||
| USAGE__description=' | ||||
| 	interactively unmount an AWS EFS volume to the local filesystem | ||||
| ' | ||||
|  | ||||
| MAIN() { | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 	########################################## | ||||
|  | ||||
| 	[ ! -d "${AWS__EFS__LOCAL_MOUNT_POINT}" ] && { | ||||
| 		echo.status 'no efs currently mounted' | ||||
| 		return 0 | ||||
| 	[ ! -d "$AWS__EFS__LOCAL_MOUNT_POINT" ] && { | ||||
| 		STATUS 'no efs currently mounted' | ||||
| 		exit 0 | ||||
| 	} | ||||
|  | ||||
| 	local MOUNTED=$(cd -- "${AWS__EFS__LOCAL_MOUNT_POINT}" | find . -type -f | sed 's|^\./.||') | ||||
| 	[ "${MOUNTED}" ] && { | ||||
| 		echo.status 'no efs currently mounted' | ||||
| 		return 0 | ||||
| 	local MOUNTED=$(ls "$AWS__EFS__LOCAL_MOUNT_POINT") | ||||
| 	[ ! $MOUNTED ] && { | ||||
| 		STATUS 'no efs currently mounted' | ||||
| 		exit 0 | ||||
| 	} | ||||
|  | ||||
| 	utils.io.getsudo || return 1 | ||||
| 	GETSUDO || exit 1 | ||||
|  | ||||
| 	local SELECTED=$(echo ${MOUNTED} | utils.fzf 'select a file system to unmount') | ||||
| 	[ "${SELECTED}" ] || user.abort | ||||
|  | ||||
| 	local EFS="${AWS__EFS__LOCAL_MOUNT_POINT}/${SELECTED}" | ||||
| 	echo.status "unmounting '${SELECTED}'" | ||||
| 	sudo umount "${EFS}" >/dev/null 2>&1 | ||||
| 	sudo rmdir -- "${EFS}" \ | ||||
| 		&& echo.success "done" \ | ||||
| 		|| utils.fail 2 "failed to unmount '${EFS}'" | ||||
| 	local SELECTED=$(echo $MOUNTED | FZF 'select a file system to unmount') | ||||
| 	[ ! $SELECTED ] && ABORT | ||||
|  | ||||
| 	local EFS="$AWS__EFS__LOCAL_MOUNT_POINT/$SELECTED" | ||||
| 	STATUS "unmounting '$SELECTED'" | ||||
| 	sudo umount $EFS >/dev/null 2>&1 | ||||
| 	sudo rmdir $EFS \ | ||||
| 		&& SUCCESS "done" \ | ||||
| 		|| FAIL 2 "failed to unmount '$EFS'" | ||||
| } | ||||
|   | ||||
| @@ -1,86 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/eks/cluster-login | ||||
| 
 | ||||
| use cloud/aws/zshparse | ||||
| use cloud/aws/eks/zshparse | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local DESCRIPTION=" | ||||
| 		Context wrapper for kubernetes CLI commands on AWS EKS. This | ||||
| 		will automatically attempt login for first-time connections, | ||||
| 		and ensures the correct kubecontext is used for the expected | ||||
| 		command. | ||||
| 
 | ||||
| 			EKS --cluster-name my-cluster kubectl get pods | ||||
| 			EKS --cluster-name my-cluster helm history my-deployment | ||||
| 			... etc ... | ||||
| 		" | ||||
| 	local ARGS=() PARSERS=( | ||||
| 		cloud.aws.zshparse.overrides | ||||
| 		cloud.aws.eks.zshparse.cluster-name | ||||
| 	) | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	local CONTEXT="arn:aws:eks:${REGION}:${ACCOUNT}:cluster/${CLUSTER_NAME}" | ||||
| 
 | ||||
| 	local ALREADY_LOGGED_IN | ||||
| 	kubectl config get-contexts --output=name | grep -q "^${CONTEXT}$" \ | ||||
| 		&& ALREADY_LOGGED_IN=true \ | ||||
| 		|| ALREADY_LOGGED_IN=false \ | ||||
| 		; | ||||
| 
 | ||||
| 	case ${ALREADY_LOGGED_IN} in | ||||
| 		( true ) ;; | ||||
| 		( false ) | ||||
| 			cloud.aws.eks.cluster-login \ | ||||
| 					${AWS_PASSTHROUGH[@]} \ | ||||
| 					--cluster-name ${CLUSTER_NAME} \ | ||||
| 					>/dev/null \ | ||||
| 				|| echo.error "unable to login to cluster '${CLUSTER_NAME}'" \ | ||||
| 				|| return 1 | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	local CONTEXT_ARGS=() | ||||
| 	case ${KUBECLI} in | ||||
| 		( helm ) | ||||
| 			CONTEXT_ARGS+=(--kube-context ${CONTEXT})  # *rolls eyes* THANKS, helm | ||||
| 			;; | ||||
| 		( * ) | ||||
| 			CONTEXT_ARGS+=(--context ${CONTEXT}) | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	${KUBECLI} ${CONTEXT_ARGS[@]} ${ARGS[@]} | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { return 0; } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.locals() { | ||||
| 	local KUBECLI   # extracted from default ARGS parser | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.usage() { | ||||
| 	USAGE__usage+=' kubecli [...kubecli-args...]' | ||||
| 
 | ||||
| 	USAGE__args+=' | ||||
| 		kubecli        cli which uses kubernetes context arguments (e.g. kubectl, helm, flux) | ||||
| 		kubecli-args   arguments forwarded to the kubectl-style CLI | ||||
| 	' | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.validate() { | ||||
| 	KUBECLI="${ARGS[1]}" | ||||
| 	ARGS=(${ARGS[@]:1}) | ||||
| 
 | ||||
| 	[ ${KUBECLI} ] \ | ||||
| 		|| echo.error "missing argument for 'kubecli'" | ||||
| } | ||||
| @@ -1,105 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| 
 | ||||
| testmodule=cloud.aws.eks.cli | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eks/cli | ||||
| 	use cloud/aws/eks/cluster-login | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock cloud.aws.eks.cluster-login | ||||
| 
 | ||||
| 	_CLUSTER_NAME=$(uuidgen) | ||||
| 
 | ||||
| 	_AWS_ACCOUNT=$(uuidgen) | ||||
| 	_AWS_PROFILE=$(uuidgen) | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	_KUBECLI=$(uuidgen) | ||||
| 	_KUBECLI_ARGS=($(uuidgen) $(uuidgen) $(uuidgen)) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value ${_AWS_ACCOUNT} | ||||
| 	unittest.mock.env AWS_PROFILE --value ${_AWS_PROFILE} | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| 
 | ||||
| 	_EXPECTED_KUBECONTEXT="arn:aws:eks:${_AWS_REGION}:${_AWS_ACCOUNT}:cluster/${_CLUSTER_NAME}" | ||||
| 	_KUBECTL_KUBECONTEXTS="$(uuidgen)\n${_EXPECTED_KUBECONTEXT}\n$(uuidgen)" | ||||
| 
 | ||||
| 	_EXPECTED_AWS_ARGS=( | ||||
| 		--account ${_AWS_ACCOUNT} | ||||
| 		--region  ${_AWS_REGION} | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset \ | ||||
| 		_CLUSTER_NAME \ | ||||
| 		_AWS_ACCOUNT _AWS_PROFILE _AWS_REGION \ | ||||
| 		_EXPECTED_AWS_ARGS \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| mock.kubectl() { | ||||
| 	unittest.mock kubectl --stdout "${_KUBECTL_KUBECONTEXTS}" | ||||
| } | ||||
| 
 | ||||
| mock.kubecli() { | ||||
| 	command -v ${_KUBECLI} &>/dev/null || ${_KUBECLI}() { true; } | ||||
| 	unittest.mock ${_KUBECLI} | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.uses-correct-kubecli-args() { | ||||
| 	mock.kubectl | ||||
| 	mock.kubecli | ||||
| 
 | ||||
| 	${testmodule} --cluster-name ${_CLUSTER_NAME} ${_KUBECLI} ${_KUBECLI_ARGS[@]} | ||||
| 
 | ||||
| 	${_KUBECLI}.assert.callstack \ | ||||
| 		--context ${_EXPECTED_KUBECONTEXT} \ | ||||
| 		${_KUBECLI_ARGS[@]} | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.uses-correct-helm-args() { | ||||
| 	_KUBECLI=helm | ||||
| 
 | ||||
| 	mock.kubectl | ||||
| 	mock.kubecli | ||||
| 
 | ||||
| 	${testmodule} --cluster-name ${_CLUSTER_NAME} ${_KUBECLI} ${_KUBECLI_ARGS[@]} | ||||
| 
 | ||||
| 	${_KUBECLI}.assert.callstack \ | ||||
| 		--kube-context ${_EXPECTED_KUBECONTEXT} \ | ||||
| 		${_KUBECLI_ARGS[@]} | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.performs-login() { | ||||
| 	_KUBECTL_KUBECONTEXTS="$(uuidgen)\n$(uuidgen)" | ||||
| 
 | ||||
| 	mock.kubectl | ||||
| 	mock.kubecli | ||||
| 
 | ||||
| 	${testmodule} --cluster-name ${_CLUSTER_NAME} ${_KUBECLI} ${_KUBECLI_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eks.cluster-login.assert.callstack \ | ||||
| 		${_EXPECTED_AWS_ARGS[@]} \ | ||||
| 		--cluster-name ${_CLUSTER_NAME} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.does-not-perform-login-if-already-logged-in() { | ||||
| 	mock.kubectl | ||||
| 	mock.kubecli | ||||
| 
 | ||||
| 	${testmodule} --cluster-name ${_CLUSTER_NAME} ${_KUBECLI} ${_KUBECLI_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eks.cluster-login.assert.not.called | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/cli | ||||
| 
 | ||||
| use cloud/aws/zshparse | ||||
| use cloud/aws/eks/zshparse | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local DESCRIPTION=' | ||||
| 		Interactively sets the default kubeconfig to match the selected | ||||
| 		cluster in EKS. Also creates the kubeconfig entry if it does not | ||||
| 		already exist. | ||||
| 	' | ||||
| 	local PARSERS=( | ||||
| 		cloud.aws.zshparse.overrides | ||||
| 		cloud.aws.eks.zshparse.cluster-name | ||||
| 	) | ||||
| 
 | ||||
| 	local EKS_CLUSTER_NAME_INTERACTIVE=allowed | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	##################################################################### | ||||
| 
 | ||||
| 	[ ${CLUSTER_NAME} ] || CLUSTER_NAME=$(\ | ||||
| 		${AWS} eks list-clusters \ | ||||
| 			| jq -r '.[] | .[]' \ | ||||
| 			| utils.fzf "select an eks cluster (${ACCOUNT}/${REGION})" | ||||
| 	) | ||||
| 
 | ||||
| 	[ ${CLUSTER_NAME} ] || echo.error 'must select a valid cluster or use --cluster-name' | ||||
| 
 | ||||
| 	utils.check-errors || return $? | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	echo.status 'updating kubeconfig for EKS cluster '${CLUSTER_NAME}'' | ||||
| 	${AWS} eks update-kubeconfig --name ${CLUSTER_NAME} \ | ||||
| 		&& echo.success "kubeconfig updated with '${CLUSTER_NAME}'" \ | ||||
| 		|| echo.error "failed to update kubeconfig; do you have permission to access '${CLUSTER_NAME}'?" | ||||
| } | ||||
| @@ -1,66 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eks.cluster-login | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eks/cluster-login | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock cloud.aws.cli | ||||
| 
 | ||||
| 	_CLUSTER_NAME=$(uuidgen) | ||||
| 
 | ||||
| 	_AWS_ACCOUNT=$(uuidgen) | ||||
| 	_AWS_PROFILE=$(uuidgen) | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value ${_AWS_ACCOUNT} | ||||
| 	unittest.mock.env AWS_PROFILE --value ${_AWS_PROFILE} | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| 
 | ||||
| 	_EXPECTED_AWS_ARGS=( | ||||
| 		--account ${_AWS_ACCOUNT} | ||||
| 		--region  ${_AWS_REGION} | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset \ | ||||
| 		_CLUSTER_NAME \ | ||||
| 		_AWS_ACCOUNT _AWS_PROFILE _AWS_REGION \ | ||||
| 		_EXPECTED_AWS_ARGS \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.login-to-correct-cluster() { | ||||
| 	${testmodule} --cluster-name ${_CLUSTER_NAME} | ||||
| 
 | ||||
| 	cloud.aws.cli.assert.callstack \ | ||||
| 		${_EXPECTED_AWS_ARGS[@]} \ | ||||
| 		eks update-kubeconfig \ | ||||
| 		--name ${_CLUSTER_NAME} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.interactive-login-ignored-on-ci() { | ||||
| 	${testmodule} | ||||
| 	cloud.aws.cli.assert.not.called | ||||
| } | ||||
| 
 | ||||
| test.interactive-login-to-correct-cluster() { | ||||
| 	unittest.mock utils.fzf --stdout ${_CLUSTER_NAME} | ||||
| 
 | ||||
| 	${testmodule} | ||||
| 
 | ||||
| 	cloud.aws.cli.assert.callstack \ | ||||
| 		${_EXPECTED_AWS_ARGS[@]} \ | ||||
| 		eks update-kubeconfig \ | ||||
| 		--name ${_CLUSTER_NAME} \ | ||||
| 		; | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| # | ||||
| # run kubectl/helm/etc commands on AWS Elastic Kubernetes Service (EKS) | ||||
| # | ||||
| 
 | ||||
| # provides an EKS connection wrapper for any kubectl-like cli | ||||
| use cloud/aws/eks/cli | ||||
| eval "${scwryptsmodule}() { ${scwryptsmodule}.cli $@; }" | ||||
| 
 | ||||
| # sets up kubeconfig to connect to EKS | ||||
| use cloud/aws/eks/cluster-login | ||||
| @@ -1,24 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eks | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.provides-eks-cli() { | ||||
| 	unittest.test.provides ${testmodule}.cli | ||||
| } | ||||
| 
 | ||||
| test.provides-eks-cli-alias() { | ||||
| 	unittest.test.provides ${testmodule} | ||||
| } | ||||
| 
 | ||||
| test.provides-cluster-login() { | ||||
| 	unittest.test.provides ${testmodule}.cluster-login | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use cloud/aws/eks | ||||
| ##################################################################### | ||||
|  | ||||
|   | ||||
| @@ -1,44 +0,0 @@ | ||||
| ${scwryptsmodule}.locals() { | ||||
| 	local CLUSTER_NAME | ||||
| 
 | ||||
| 	# set to 'allowed' to enable interactive cluster select | ||||
| 	# by default, the '--cluster-name' flag is required | ||||
| 	local EKS_CLUSTER_NAME_INTERACTIVE | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSED=0 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		( -c | --cluster-name ) | ||||
| 			CLUSTER_NAME="$2" | ||||
| 			((PARSED+=2)) | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return $PARSED | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.usage() { | ||||
| 	[[ "$USAGE__usage" =~ '\[...options...\]' ]] || USAGE__usage+=' [...options...]' | ||||
| 
 | ||||
| 	USAGE__options+="\n | ||||
| 		-c, --cluster-name <string>   EKS cluster name identifier string | ||||
| 	" | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.validate() { | ||||
| 	[ $CLUSTER_NAME ] && return 0 | ||||
| 
 | ||||
| 	[[ $EKS_CLUSTER_NAME_INTERACTIVE =~ allowed ]] \ | ||||
| 		|| echo.error 'missing cluster name' \ | ||||
| 		|| return | ||||
| 
 | ||||
| 	CLUSTER_NAME=$(\ | ||||
| 		$AWS eks list-clusters \ | ||||
| 			| jq -r '.[] | .[]' \ | ||||
| 			| utils.fzf "select an eks cluster ($ACCOUNT/$REGION)" \ | ||||
| 	) | ||||
| 
 | ||||
| 	[ $CLUSTER_NAME ] || echo.error 'must select a valid cluster or use --cluster-name' | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| # | ||||
| # argument parsers for common EKS arguments | ||||
| # | ||||
| 
 | ||||
| # get the EKS "ClusterName" identifier | ||||
| use cloud/aws/eks/zshparse/cluster-name | ||||
| @@ -1,40 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/zshparse/overrides | ||||
| 
 | ||||
| DEPENDENCIES+=(eksctl) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSERS=(cloud.aws.zshparse.overrides) | ||||
| 	local DESCRIPTION=" | ||||
| 		Context wrapper for eksctl commands; prevents accidental local environment | ||||
| 		bleed-through, but otherwise works exactly like 'eksctl'. | ||||
| 
 | ||||
| 		This wrapper should be used in place of _all_ 'eksctl' usages within scwrypts. | ||||
| 	" | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	echo.debug "invoking '$(echo "$AWS_EVAL_PREFIX" | sed 's/AWS_\(ACCESS_KEY_ID\|SECRET_ACCESS_KEY\)=[^ ]\+ //g')eksctl ${ARGS[@]}'" | ||||
| 	eval "${AWS_EVAL_PREFIX}eksctl ${ARGS[@]}" | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.locals() { | ||||
| 	local ARGS=() | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.usage() { | ||||
| 	USAGE__args+=' | ||||
| 		args   all remaining arguments are forwarded to eksctl | ||||
| 	' | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eksctl.cli | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eksctl/cli | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock eksctl | ||||
| 	unittest.mock echo.debug | ||||
| 
 | ||||
| 	_ARGS=($(uuidgen) $(uuidgen) $(uuidgen)) | ||||
| 
 | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 	_AWS_PROFILE=$(uuidgen) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value $(uuidgen) | ||||
| 	unittest.mock.env AWS_PROFILE --value ${_AWS_PROFILE} | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset _AWS_REGION | ||||
| 	unset _AWS_PROFILE | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.forwards-arguments() { | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	eksctl.assert.callstack \ | ||||
| 		${_ARGS[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.forwards-profile() { | ||||
| 	# | ||||
| 	# --profile is an invalid argument for eksctl, so it | ||||
| 	# MUST be forwarded as AWS_PROFILE to prevent environment | ||||
| 	# bleeding | ||||
| 	# | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	echo.debug.assert.callstackincludes \ | ||||
| 		AWS_PROFILE=${OVERRIDE_REGION} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.overrides-region() { | ||||
| 	local OVERRIDE_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	${testmodule} --region ${OVERRIDE_REGION} ${_ARGS[@]} | ||||
| 
 | ||||
| 	echo.debug.assert.callstackincludes \ | ||||
| 		AWS_REGION=${OVERRIDE_REGION} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.overrides-account() { | ||||
| 	local OVERRIDE_ACCOUNT=$(uuidgen) | ||||
| 
 | ||||
| 	${testmodule} --account ${OVERRIDE_ACCOUNT} ${_ARGS[@]} | ||||
| 
 | ||||
| 	echo.debug.assert.callstackincludes \ | ||||
| 		AWS_ACCOUNT=${OVERRIDE_ACCOUNT} \ | ||||
| 		; | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| # | ||||
| # module for eksctl actions | ||||
| # | ||||
| 
 | ||||
| # context wrapper for direct use of eksctl | ||||
| use cloud/aws/eksctl/cli | ||||
| eval "${scwryptsmodule}() { ${scwryptsmodule}.cli \$@; }" | ||||
| 
 | ||||
| # argument helper for creating a standard iamserviceaccount | ||||
| use cloud/aws/eksctl/iamserviceaccount | ||||
| @@ -1,20 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eksctl | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eksctl | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.provides-eksctl-cli() { | ||||
| 	unittest.test.provides ${testmodule}.cli | ||||
| } | ||||
| 
 | ||||
| test.provides-eksctl-alias() { | ||||
| 	unittest.test.provides ${testmodule} | ||||
| } | ||||
| @@ -1,57 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/eks/cli | ||||
| 
 | ||||
| use cloud/aws/eksctl/iamserviceaccount/zshparse | ||||
| use cloud/aws/zshparse/overrides | ||||
| 
 | ||||
| DEPENDENCIES+=(kubectl yq) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local DESCRIPTION=" | ||||
| 		determine whether the target iamserviceaccount already | ||||
| 		exists on Kubernetes | ||||
| 
 | ||||
| 		OK: | ||||
| 		  exit code   0 : the serviceaccount exists on kubernetes | ||||
| 		  exit code 100 : the serviceaccount does not exist on kubernetes | ||||
| 
 | ||||
| 		ERROR: | ||||
| 		  exit code 200 : the serviceaccount exists on kubernetes, but does not match the target role | ||||
| 	" | ||||
| 
 | ||||
| 	local PARSERS=( | ||||
| 		cloud.aws.eksctl.iamserviceaccount.zshparse | ||||
| 		cloud.aws.zshparse.overrides | ||||
| 	) | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	echo.status "checking for existing role-arn" | ||||
| 	local CURRENT_ROLE_ARN=$( | ||||
| 		cloud.aws.eks.cli kubectl ${AWS_PASSTHROUGH_ARGS[@]} --namespace "${NAMESPACE}" get serviceaccount "${SERVICEACCOUNT}" -o yaml \ | ||||
| 			| utils.yq -r '.metadata.annotations["eks.amazonaws.com/role-arn"]' \ | ||||
| 			| grep -v '^null$' \ | ||||
| 	) | ||||
| 
 | ||||
| 	[ "${CURRENT_ROLE_ARN}" ] || { | ||||
| 		echo.status "serviceaccount does not exist or has no configured role" | ||||
| 		return 100 | ||||
| 	} | ||||
| 
 | ||||
| 	[[ ${CURRENT_ROLE_ARN} =~ "${ROLE_NAME}$" ]] || { | ||||
| 		echo.status "\ | ||||
| 			serviceaccount current role does not match desired role: | ||||
| 			  CURRENT : ${CURRENT_ROLE_ARN} | ||||
| 			  DESIRED : arn:aws:iam::${AWS_ACCOUNT}:role/${ROLE_NAME} | ||||
| 		" | ||||
| 		return 200 | ||||
| 	} | ||||
| 
 | ||||
| 	echo.status "serviceaccount current role matches desired role" | ||||
| 	return 0 | ||||
| } | ||||
| @@ -1,63 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eksctl.iamserviceaccount.check-exists | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eksctl/iamserviceaccount/check-exists | ||||
| 	use cloud/aws/eks/cli | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	_SERVICEACCOUNT=$(uuidgen) | ||||
| 	_NAMEPACE=$(uuidgen) | ||||
| 	_ROLE_NAME=$(uuidgen) | ||||
| 	_ROLE_ARN="$(uuidgen)/${_ROLE_NAME}" | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value $(uuidgen) | ||||
| 	unittest.mock.env AWS_PROFILE --value $(uuidgen) | ||||
| 	unittest.mock.env AWS_REGION  --value $(uuidgen) | ||||
| 
 | ||||
| 	_ARGS=( | ||||
| 		--serviceaccount ${_SERVICEACCOUNT} | ||||
| 		--namespace ${_NAMEPACE} | ||||
| 		--role-name ${_ROLE_NAME} | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset _SERVICEACCOUNT _NAMESPACE _ROLE_NAME _ARGS | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.detects-exists() { | ||||
| 	unittest.mock cloud.aws.eks.cli \ | ||||
| 		--stdout '{"metadata":{"annotations":{"eks.amazonaws.com/role-arn":"'$_ROLE_ARN'"}}}' \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	[[ $? -eq 0 ]] | ||||
| } | ||||
| 
 | ||||
| test.detects-not-exists() { | ||||
| 	unittest.mock cloud.aws.eks.cli \ | ||||
| 		--stdout '{}' | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	[[ $? -eq 100 ]] | ||||
| } | ||||
| 
 | ||||
| test.detects-exists-but-does-not-match() { | ||||
| 	unittest.mock cloud.aws.eks.cli \ | ||||
| 		--stdout '{"metadata":{"annotations":{"eks.amazonaws.com/role-arn":"'$(uuidgen)'"}}}' \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	[[ $? -eq 200 ]] | ||||
| } | ||||
| @@ -1,93 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use cloud/aws/eksctl/cli | ||||
| use cloud/aws/eksctl/iamserviceaccount/check-exists | ||||
| 
 | ||||
| use cloud/aws/eksctl/iamserviceaccount/zshparse | ||||
| use cloud/aws/zshparse/overrides | ||||
| use cloud/aws/eks/zshparse/cluster-name | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local DESCRIPTION=" | ||||
| 		creates an 'iamserviceaccount' which provides a Kubernetes | ||||
| 		serviceaccount with AWS role identity and access control | ||||
| 	" | ||||
| 
 | ||||
| 	local PARSERS=( | ||||
| 		cloud.aws.eksctl.iamserviceaccount.zshparse | ||||
| 		cloud.aws.zshparse.overrides | ||||
| 		cloud.aws.eks.zshparse.cluster-name | ||||
| 	) | ||||
| 
 | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	case ${FORCE} in | ||||
| 		( true ) ;; | ||||
| 		( false ) | ||||
| 			cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 				--serviceaccount "${SERVICEACCOUNT}" \ | ||||
| 				--namespace      "${NAMESPACE}" \ | ||||
| 				--role-name      "${ROLE_NAME}" \ | ||||
| 				${AWS_PASSTHROUGH[@]} \ | ||||
| 				; | ||||
| 			case $? in | ||||
| 				(   0 ) echo.success "'${NAMESPACE}/${SERVICEACCOUNT}' already configured with '${ROLE_NAME}'" | ||||
| 					return 0 | ||||
| 					;; | ||||
| 				( 100 ) # role does not exist yet; continue with rollout | ||||
| 					;; | ||||
| 				( 200 ) echo.error "'${NAMESPACE}/${SERVICEACCOUNT}' has been configured with a different role than '${ROLE_NAME}'" | ||||
| 					echo.reminder "must use --force flag to overwrite" | ||||
| 					return 2 | ||||
| 					;; | ||||
| 			esac | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	echo.status "creating iamserviceaccount" \ | ||||
| 		&& cloud.aws.eksctl.cli ${AWS_PASSTHROUGH_ARGS[@]} create iamserviceaccount \ | ||||
| 			--cluster   "${CLUSTER_NAME}" \ | ||||
| 			--namespace "${NAMESPACE}" \ | ||||
| 			--name      "${SERVICEACCOUNT}" \ | ||||
| 			--role-name "${ROLE_NAME}" \ | ||||
| 			--override-existing-serviceaccounts \ | ||||
| 			--approve \ | ||||
| 			${ARGS[@]} \ | ||||
| 		&& echo.success "successfully configured '${NAMESPACE}/${SERVICEACCOUNT}' with IAM role '${ROLE_NAME}'" \ | ||||
| 		|| echo.error   "unable to configure '${NAMESPACE}/${SERVICEACCOUNT}' with IAM role '${ROLE_NAME}'\n(check cloudformation dashboard for details)" \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.locals() { | ||||
| 	local FORCE=false   # whether or not to force a new eksctl deployment | ||||
| 	local ARGS=() | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { | ||||
| 	local PARSED=0 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		--force ) PARSED=1; FORCE=true ;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return ${PARSED} | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.usage() { | ||||
| 	USAGE__options+=" | ||||
| 		--force   don't check for existing serviceaccount and override any existing configuration | ||||
| 	" | ||||
| 
 | ||||
| 	USAGE__args+=" | ||||
| 		args   all remaining arguments are forwarded to 'eksctl create iamserviceaccount' | ||||
| 
 | ||||
| 		eksctl create iamserviceaccount args: | ||||
| 		$(eksctl create iamserviceaccount --help 2>&1 | grep -v -- '--name' | grep -v -- '--namespace' | grep -v -- '--role-name' | sed 's/^/  /') | ||||
| 	" | ||||
| } | ||||
| @@ -1,150 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eksctl.iamserviceaccount.create | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eksctl/iamserviceaccount/create | ||||
| } | ||||
| 
 | ||||
| beforeeach() { | ||||
| 	unittest.mock cloud.aws.eksctl.cli | ||||
| 
 | ||||
| 	_SERVICEACCOUNT=$(uuidgen) | ||||
| 	_NAMESPACE=$(uuidgen) | ||||
| 	_ROLE_NAME=$(uuidgen) | ||||
| 	_ROLE_ARN="$(uuidgen)/${_ROLE_NAME}" | ||||
| 
 | ||||
| 	_CLUSTER_NAME=$(uuidgen) | ||||
| 
 | ||||
| 	_AWS_ACCOUNT=$(uuidgen) | ||||
| 	_AWS_REGION=$(uuidgen) | ||||
| 
 | ||||
| 	unittest.mock.env AWS_ACCOUNT --value ${_AWS_ACCOUNT} | ||||
| 	unittest.mock.env AWS_PROFILE --value $(uuidgen) | ||||
| 	unittest.mock.env AWS_REGION  --value ${_AWS_REGION} | ||||
| 
 | ||||
| 	_IAMSERVICEACCOUNT_ARGS=( | ||||
| 		--serviceaccount ${_SERVICEACCOUNT} | ||||
| 		--namespace ${_NAMESPACE} | ||||
| 		--role-name ${_ROLE_NAME} | ||||
| 	) | ||||
| 
 | ||||
| 	_EXTRA_ARGS=($(uuidgen) $(uuidgen) $(uuidgen)) | ||||
| 
 | ||||
| 	_ARGS=( | ||||
| 		--cluster-name ${_CLUSTER_NAME} | ||||
| 		${_IAMSERVICEACCOUNT_ARGS[@]} | ||||
| 		-- | ||||
| 		${_EXTRA_ARGS[@]} | ||||
| 	) | ||||
| 
 | ||||
| 	_EXPECTED_AWS_PASSTHROUGH=( | ||||
| 		--account ${_AWS_ACCOUNT} | ||||
| 		--region  ${_AWS_REGION} | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| aftereach() { | ||||
| 	unset \ | ||||
| 		_SERVICEACCOUNT _NAMESPACE _ROLE_NAME \ | ||||
| 		_CLUSTER_NAME \ | ||||
| 		_AWS_ACCOUNT _AWS_REGION \ | ||||
| 		_ARGS _EXPECTED_AWS_PASSTHROUGH_ARGS \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.performs-check-exists() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 0 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eksctl.iamserviceaccount.check-exists.assert.callstack \ | ||||
| 		${_IAMSERVICEACCOUNT_ARGS[@]} \ | ||||
| 		${_EXPECTED_AWS_PASSTHROUGH[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.ignores-check-exist-on-force() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 0 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} --force | ||||
| 
 | ||||
| 	cloud.aws.eksctl.iamserviceaccount.check-exists.assert.not.called | ||||
| } | ||||
| 
 | ||||
| test.does-not-create-if-exists() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 0 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eksctl.cli.assert.not.called | ||||
| } | ||||
| 
 | ||||
| test.creates-role() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 100 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eksctl.cli.assert.callstack \ | ||||
| 		create iamserviceaccount \ | ||||
| 		--cluster   ${_CLUSTER_NAME} \ | ||||
| 		--namespace ${_NAMESPACE} \ | ||||
| 		--name      ${_SERVICEACCOUNT} \ | ||||
| 		--role-name ${_ROLE_NAME} \ | ||||
| 		--override-existing-serviceaccounts \ | ||||
| 		--approve \ | ||||
| 		${_EXTRA_ARGS[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.creates-role-on-force() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 0 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} --force | ||||
| 
 | ||||
| 	cloud.aws.eksctl.cli.assert.callstack \ | ||||
| 		create iamserviceaccount \ | ||||
| 		--cluster   ${_CLUSTER_NAME} \ | ||||
| 		--namespace ${_NAMESPACE} \ | ||||
| 		--name      ${_SERVICEACCOUNT} \ | ||||
| 		--role-name ${_ROLE_NAME} \ | ||||
| 		--override-existing-serviceaccounts \ | ||||
| 		--approve \ | ||||
| 		${_EXTRA_ARGS[@]} \ | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| test.does-not-create-if-mismatched-role() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 200 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	cloud.aws.eksctl.cli.assert.not.called | ||||
| } | ||||
| 
 | ||||
| test.returns-correct-error-if-mismatched-role() { | ||||
| 	unittest.mock cloud.aws.eksctl.iamserviceaccount.check-exists \ | ||||
| 		--exit-code 200 \ | ||||
| 		; | ||||
| 
 | ||||
| 	${testmodule} ${_ARGS[@]} | ||||
| 
 | ||||
| 	[[ $? -eq 2 ]] | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| # | ||||
| # build 'iamserviceaccount' to enable IAM identity / access control | ||||
| # | ||||
| 
 | ||||
| # create the iamserviceaccount | ||||
| use cloud/aws/eksctl/iamserviceaccount/create | ||||
| 
 | ||||
| # check whether the iamserviceaccount exists in kubernetes | ||||
| use cloud/aws/eksctl/iamserviceaccount/check-exists | ||||
| @@ -1,20 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use unittest | ||||
| testmodule=cloud.aws.eksctl.iamserviceaccount | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| beforeall() { | ||||
| 	use cloud/aws/eksctl/iamserviceaccount | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| test.provides-create() { | ||||
| 	unittest.test.provides ${testmodule}.create | ||||
| } | ||||
| 
 | ||||
| test.provides-check-exists() { | ||||
| 	unittest.test.provides ${testmodule}.check-exists | ||||
| } | ||||
| @@ -1,35 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.locals() { | ||||
| 	local SERVICEACCOUNT | ||||
| 	local NAMESPACE | ||||
| 	local ROLE_NAME | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSED=0 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		( --serviceaccount ) PARSED=2; SERVICEACCOUNT=$2 ;; | ||||
| 		( --namespace      ) PARSED=2; NAMESPACE=$2 ;; | ||||
| 		( --role-name      ) PARSED=2; ROLE_NAME=$2 ;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return ${PARSED} | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.usage() { | ||||
| 	USAGE__options+=" | ||||
| 		--serviceaccount   (required) target k8s:ServiceAccount | ||||
| 		--namespace        (required) target k8s:Namespace | ||||
| 		--role-name        (required) name of the IAM role to assign | ||||
| 	" | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.validate() { | ||||
| 	[ "${SERVICEACCOUNT}" ] || echo.error "--serviceaccount is required" | ||||
| 	[ "${NAMESPACE}"      ] || echo.error "--namespace is required" | ||||
| 	[ "${ROLE_NAME}"      ] || echo.error "--role-name is required" | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use cloud/aws/rds | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use cloud/aws/rds | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use cloud/aws/rds | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|   | ||||
| @@ -1,30 +1,33 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(cli53) | ||||
| REQUIRED_ENV+=(AWS_PROFILE AWS_ACCOUNT) | ||||
| REQUIRED_ENV+=(AWS_PROFILE) | ||||
| ##################################################################### | ||||
|  | ||||
| utils.cli53() { | ||||
| 	AWS_ACCOUNT=${AWS_ACCOUNT} \ | ||||
| 		cli53 --profile ${AWS_PROFILE} $@; | ||||
| } | ||||
|  | ||||
| MAIN() { | ||||
| 	local BACKUP_BASE_PATH="${SCWRYPTS_DATA_PATH}/route53-backup/${SCWRYPTS_ENV}" | ||||
| 	local BACKUP_PATH="$SCWRYPTS_OUTPUT_PATH/$ENV_NAME/aws-dns-backup/$(date '+%Y-%m-%d')" | ||||
| 	mkdir -p $BACKUP_PATH >/dev/null 2>&1 | ||||
|  | ||||
| 	local DOMAIN | ||||
| 	local JOBS=() | ||||
| 	for DOMAIN in $(utils.cli53 list | awk '{print $2;}' | sed '1d; s/\.$//') | ||||
| 	for DOMAIN in $(ROUTE53_GET_DOMAINS) | ||||
| 	do | ||||
| 		( | ||||
| 			utils.cli53 export ${DOMAIN} > "${BACKUP_BASE_PATH}/${DOMAIN}/$(date '+%Y-%m-%d_%H%M').cli53.txt" \ | ||||
| 				&& echo.success "backed up '${DOMAIN}'" \ | ||||
| 				|| echo.error "failed to back up '${DOMAIN}'" \ | ||||
| 		( STATUS "creating '$BACKUP_PATH/$DOMAIN.txt'" \ | ||||
| 			&& cli53 export --profile $AWS_PROFILE $DOMAIN > "$BACKUP_PATH/$DOMAIN.txt" \ | ||||
| 			&& SUCCESS "backed up '$DOMAIN'" \ | ||||
| 			|| ERROR "failed to back up '$DOMAIN'" \ | ||||
| 		) & | ||||
| 		JOBS+=$! | ||||
| 	done | ||||
|  | ||||
| 	local P | ||||
| 	for P in ${JOBS[@]}; do wait ${P} &>/dev/null; done | ||||
|  | ||||
| 	echo.reminder "successful backups can be found in '${BACKUP_BASE_PATH}'" | ||||
| 	for P in ${JOBS[@]}; do wait $P >/dev/null 2>&1; done | ||||
| } | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| ROUTE53_GET_DOMAINS() { | ||||
| 	cli53 list --profile $AWS_PROFILE \ | ||||
| 		| awk '{print $2;}' \ | ||||
| 		| sed '1d; s/\.$//'\ | ||||
| 		; | ||||
| } | ||||
|   | ||||
| @@ -1,79 +0,0 @@ | ||||
| ${scwryptsmodule}.locals() { | ||||
| 	local ACCOUNT   # parsed/configured AWS_ACCOUNT (use this instead of the env var!) | ||||
| 	local REGION    # parsed/configured AWS_REGION (use this instead of the env var!) | ||||
| 
 | ||||
| 	local AWS_PASSTHROUGH=()   # used to forward parsed overrides to cloud.aws.cli calls (e.g. 'cloud.aws.cli ${AWS_PASSTHROUGH[@]} your command') | ||||
| 	local AWS=()               # used to forward parsed overrides to cloud.aws.cli calls (e.g. '$AWS your command') | ||||
| 
 | ||||
| 	# should only be used by cloud/aws/cli | ||||
| 	local AWS_EVAL_PREFIX | ||||
| 	local AWS_CONTEXT_ARGS=() | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSED=0 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		( --account ) PARSED+=2; ACCOUNT=$2 ;; | ||||
| 		( --region  ) PARSED+=2; REGION=$2  ;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return $PARSED | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.usage() { | ||||
| 	[[ "$USAGE__usage" =~ ' \[...options...\]' ]] || USAGE__usage+=' [...options...]' | ||||
| 
 | ||||
| 	USAGE__options+="\n | ||||
| 		--account   overrides required AWS_ACCOUNT scwrypts env value | ||||
| 		--region    overrides required AWS_REGION  scwrypts env value | ||||
| 	" | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ${scwryptsmodule}.validate() { | ||||
| 	AWS_CONTEXT_ARGS=(--output json) | ||||
| 
 | ||||
| 	[ $ACCOUNT ] || { utils.environment.check AWS_ACCOUNT &>/dev/null && ACCOUNT=$AWS_ACCOUNT; } | ||||
| 	[ $ACCOUNT ] \ | ||||
| 		&& AWS_EVAL_PREFIX+="AWS_ACCOUNT=$ACCOUNT " \ | ||||
| 		&& AWS_PASSTHROUGH+=(--account $ACCOUNT) \ | ||||
| 		|| echo.error "missing either --account or AWS_ACCOUNT" \ | ||||
| 		; | ||||
| 
 | ||||
| 	[ $REGION ] || { utils.environment.check AWS_REGION &>/dev/null && REGION=$AWS_REGION; } | ||||
| 	[ $REGION ] \ | ||||
| 		&& AWS_EVAL_PREFIX+="AWS_REGION=$REGION AWS_DEFAULT_REGION=$REGION " \ | ||||
| 		&& AWS_CONTEXT_ARGS+=(--region $REGION) \ | ||||
| 		&& AWS_PASSTHROUGH+=(--region $REGION) \ | ||||
| 		|| echo.error "missing either --region  or AWS_REGION" \ | ||||
| 		; | ||||
| 
 | ||||
| 	utils.environment.check AWS_PROFILE &>/dev/null | ||||
| 	[ $AWS_PROFILE ] \ | ||||
| 		&& AWS_EVAL_PREFIX+="AWS_PROFILE=$AWS_PROFILE " \ | ||||
| 		&& AWS_CONTEXT_ARGS+=(--profile $AWS_PROFILE) \ | ||||
| 		; | ||||
| 
 | ||||
| 	AWS=(cloud.aws.cli ${AWS_PASSTHROUGH[@]}) | ||||
| 
 | ||||
| 	[ ! $CI ] && { | ||||
| 		# non-CI must use PROFILE authentication | ||||
| 		[ $AWS_PROFILE ] || echo.error "missing either --profile or AWS_PROFILE"; | ||||
| 
 | ||||
| 		[[ $AWS_PROFILE =~ ^default$ ]] \ | ||||
| 			&& echo.warning "it is HIGHLY recommended to NOT use the 'default' profile for aws operations\nconsider using '$USER.$SCWRYPTS_ENV' instead" | ||||
| 	} | ||||
| 
 | ||||
| 	[ $CI ] && { | ||||
| 		# CI can use 'profile' or envvar 'access key' authentication | ||||
| 		[ $AWS_PROFILE ] && return 0  # 'profile' preferred | ||||
| 
 | ||||
| 		[ $AWS_ACCESS_KEY_ID ] && [ $AWS_SECRET_ACCESS_KEY ] \ | ||||
| 			&& AWS_EVAL_PREFIX+="AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID " \ | ||||
| 			&& AWS_EVAL_PREFIX+="AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY " \ | ||||
| 			&& return 0 | ||||
| 
 | ||||
| 		echo.error "running in CI, but missing both profile and access-key configuration\n(one AWS authentication method *must* be used)" | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| # | ||||
| # argument parsers for common AWS-CLI arguments | ||||
| # | ||||
| 
 | ||||
| # load/override AWS_* variables | ||||
| use cloud/aws/zshparse/overrides | ||||
							
								
								
									
										7
									
								
								zsh/cloud/media-sync/pull
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								zsh/cloud/media-sync/pull
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/bin/zsh | ||||
| use cloud/media-sync | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	MEDIA_SYNC__PULL $@ | ||||
| } | ||||
							
								
								
									
										7
									
								
								zsh/cloud/media-sync/push
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								zsh/cloud/media-sync/push
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/bin/zsh | ||||
| use cloud/media-sync | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	MEDIA_SYNC__PUSH $@ | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| scwrypts.config() { | ||||
| 	[ $1 ] || return 1 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		( python.versions ) echo "3.13\n3.12\n3.11\n3.10" ;; | ||||
| 		( nodejs.version  ) echo "22.0.0" ;; | ||||
| 		( * ) return 1 ;; | ||||
| 	esac | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										183
									
								
								zsh/config.zsh
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								zsh/config.zsh
									
									
									
									
									
								
							| @@ -1,183 +0,0 @@ | ||||
| ##################################################################### | ||||
| ### preflight config validation ##################################### | ||||
| ##################################################################### | ||||
| 
 | ||||
| [[ ${__SCWRYPT} -eq 1 ]] && return 0  # avoid config reload if already active | ||||
| 
 | ||||
| # Apparently MacOS puts ALL of the homebrew stuff inside of a top level git repository | ||||
| # with bizarre git ignores; so: | ||||
| #  - USE the git root if it's a manual install... | ||||
| #  - UNLESS that git root is just the $(brew --prefix) | ||||
| __SCWRYPTS_ROOT="$(cd -- "${0:a:h}"; git rev-parse --show-toplevel 2>/dev/null | grep -v "^$(brew --prefix 2>/dev/null)$")" | ||||
| 
 | ||||
| [ ${__SCWRYPTS_ROOT} ] && [ -d "${__SCWRYPTS_ROOT}" ] \ | ||||
| 	|| __SCWRYPTS_ROOT="$(echo "${0:a:h}" | sed -n 's|\(share/scwrypts\).*$|\1|p')" | ||||
| 
 | ||||
| [ ${__SCWRYPTS_ROOT} ] && [ -d "${__SCWRYPTS_ROOT}" ] || { | ||||
| 	echo "cannot determine scwrypts root path for current installation; aborting" | ||||
| 	exit 1 | ||||
| } | ||||
| 
 | ||||
| [ -f "${__SCWRYPTS_ROOT}/MANAGED_BY" ] \ | ||||
| 	&& readonly SCWRYPTS_INSTALLATION_TYPE=$(cat "${__SCWRYPTS_ROOT}/MANAGED_BY") \ | ||||
| 	|| readonly SCWRYPTS_INSTALLATION_TYPE=manual \ | ||||
| 	; | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| # | ||||
| # this is like a manual "use" invocation, but the import driver relies | ||||
| # on this file, so here we go ahead and do it by hand once | ||||
| # | ||||
| # equivalent to "use utils" | ||||
| # (which is unnecessary since utils are ALWAYS loaded with import.driver.zsh) | ||||
| # | ||||
| # normally more logic is necessary for "use", but utils.module.zsh is a | ||||
| # special module which supports direct-sourcing from any zsh environment | ||||
| # | ||||
| source "${__SCWRYPTS_ROOT}/zsh/utils/utils.module.zsh" | ||||
| SCWRYPTS_LIBRARY_LOADED__scwrypts__utils=true | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### scwrypts global configuration ################################### | ||||
| ##################################################################### | ||||
| 
 | ||||
| readonly SCWRYPTS_CONFIG_PATH="${XDG_CONFIG_HOME:-${HOME}/.config}/scwrypts" | ||||
| readonly SCWRYPTS_ENV_PATH="${SCWRYPTS_CONFIG_PATH}/environments" | ||||
| 
 | ||||
| readonly SCWRYPTS_DATA_PATH="${XDG_DATA_HOME:-${HOME}/.local/share}/scwrypts" | ||||
| 
 | ||||
| readonly SCWRYPTS_STATE_PATH="${XDG_STATE_HOME:-${HOME}/.local/state}/scwrypts" | ||||
| readonly SCWRYPTS_LOG_PATH="${SCWRYPTS_STATE_PATH}/logs" | ||||
| 
 | ||||
| [ -d /tmp ] \ | ||||
| 	&& readonly SCWRYPTS_TEMP_PATH="/tmp/scwrypts/${SCWRYPTS_RUNTIME_ID}" \ | ||||
| 	|| readonly SCWRYPTS_TEMP_PATH="${XDG_RUNTIME_DIR:-/run/user/${UID}}/scwrypts/${SCWRYPTS_RUNTIME_ID}" \ | ||||
| 	; | ||||
| 
 | ||||
| mkdir -p \ | ||||
| 	"${SCWRYPTS_ENV_PATH}" \ | ||||
| 	"${SCWRYPTS_LOG_PATH}" \ | ||||
| 	"${SCWRYPTS_TEMP_PATH}" \ | ||||
| 	; | ||||
| 
 | ||||
| DEFAULT_CONFIG="${__SCWRYPTS_ROOT}/zsh/config.user.zsh" | ||||
| source "${DEFAULT_CONFIG}" | ||||
| 
 | ||||
| USER_CONFIG_OVERRIDES="${SCWRYPTS_CONFIG_PATH}/config.zsh" | ||||
| 
 | ||||
| [ ! -f "${USER_CONFIG_OVERRIDES}" ] && { | ||||
| 	mkdir -p $(dirname "${USER_CONFIG_OVERRIDES}") | ||||
| 	cp "${DEFAULT_CONFIG}" "${USER_CONFIG_OVERRIDES}" | ||||
| } | ||||
| 
 | ||||
| source "${USER_CONFIG_OVERRIDES}" | ||||
| source "${__SCWRYPTS_ROOT}/zsh/config.global.zsh" | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### load groups and plugins ######################################### | ||||
| ##################################################################### | ||||
| 
 | ||||
| SCWRYPTS_GROUPS=() | ||||
| 
 | ||||
| command -v echo.warning &>/dev/null || WARNING() { echo "echo.warning : $@" >&2; } | ||||
| command -v echo.error   &>/dev/null || ERROR()   { echo "echo.error   : $@" >&2; return 1; } | ||||
| command -v utils.fail    &>/dev/null || FAIL()    { echo.error "${@:2}"; exit $1; } | ||||
| 
 | ||||
| __SCWRYPTS_GROUP_LOADERS=( | ||||
| 	"${__SCWRYPTS_ROOT}/scwrypts.scwrypts.zsh" | ||||
| ) | ||||
| 
 | ||||
| [ "${GITHUB_WORKSPACE}" ] && [ ! "${SCWRYPTS_GITHUB_NO_AUTOLOAD}" ] && { | ||||
| 	SCWRYPTS_GROUP_DIRS+=("${GITHUB_WORKSPACE}") | ||||
| } | ||||
| 
 | ||||
| for __SCWRYPTS_GROUP_DIR in ${SCWRYPTS_GROUP_DIRS[@]} | ||||
| do | ||||
| 	[ -d "${__SCWRYPTS_GROUP_DIR}" ] || continue | ||||
| 	for __SCWRYPTS_GROUP_LOADER in $(find "${__SCWRYPTS_GROUP_DIR}" -type f -name \*scwrypts.zsh) | ||||
| 	do | ||||
| 		__SCWRYPTS_GROUP_LOADERS+=("${__SCWRYPTS_GROUP_LOADER}") | ||||
| 	done | ||||
| done | ||||
| 
 | ||||
| scwrypts.config.group() { | ||||
| 	local GROUP_NAME="$1" | ||||
| 	local CONFIG_KEY="$2" | ||||
| 
 | ||||
| 	[ "$GROUP_NAME" ] && [ "$CONFIG_KEY" ] \ | ||||
| 		|| return 1 | ||||
| 
 | ||||
| 	echo ${(P)$(echo SCWRYPTS_GROUP_CONFIGURATION__${GROUP_NAME}__${CONFIG_KEY})} | ||||
| } | ||||
| 
 | ||||
| for __SCWRYPTS_GROUP_LOADER in ${__SCWRYPTS_GROUP_LOADERS} | ||||
| do | ||||
| 	__SCWRYPTS_GROUP_LOADER_REALPATH="$(readlink -f -- "${__SCWRYPTS_GROUP_LOADER}")" | ||||
| 
 | ||||
| 	[ -f "${__SCWRYPTS_GROUP_LOADER_REALPATH}" ] || { | ||||
| 		echo.warning "error loading group '${__SCWRYPTS_GROUP_LOADER}': cannot read file" | ||||
| 		continue | ||||
| 	} | ||||
| 
 | ||||
| 	__SCWRYPTS_GROUP_NAME="$(\ | ||||
| 		basename -- "${__SCWRYPTS_GROUP_LOADER_REALPATH}" \ | ||||
| 			| sed -n 's/^\([a-z][a-z0-9_]*[a-z0-9]\).scwrypts.zsh$/\1/p' \ | ||||
| 	)" | ||||
| 
 | ||||
| 	[ "$__SCWRYPTS_GROUP_NAME" ] || { | ||||
| 		echo.warning "unable to load group '${__SCWRYPTS_GROUP_LOADER_REALPATH}': invalid group name" >&2 | ||||
| 		continue | ||||
| 	} | ||||
| 
 | ||||
| 	[[ $(scwrypts.config.group "$__SCWRYPTS_GROUP_NAME" loaded) =~ true ]] && { | ||||
| 		echo.warning "unable to load group '${__SCWRYPTS_GROUP_NAME}': duplicate name" | ||||
| 		continue | ||||
| 	} | ||||
| 
 | ||||
| 	scwryptsgroup="SCWRYPTS_GROUP_CONFIGURATION__${__SCWRYPTS_GROUP_NAME}" | ||||
| 	scwryptsgrouproot="$(dirname -- "${__SCWRYPTS_GROUP_LOADER_REALPATH}")" | ||||
| 
 | ||||
| 	: \ | ||||
| 		&& readonly ${scwryptsgroup}__root="${scwryptsgrouproot}" \ | ||||
| 		&& source "${__SCWRYPTS_GROUP_LOADER_REALPATH}" \ | ||||
| 		&& SCWRYPTS_GROUPS+=(${__SCWRYPTS_GROUP_NAME}) \ | ||||
| 		&& readonly ${scwryptsgroup}__loaded=true \ | ||||
| 		|| echo.warning "error encountered when loading group '${__SCWRYPTS_GROUP_NAME}'" \ | ||||
| 		; | ||||
| 
 | ||||
| 	[[ ! ${__SCWRYPTS_GROUP_NAME} =~ ^scwrypts$ ]] && [ ! "$(scwrypts.config.group ${__SCWRYPTS_GROUP_NAME} zshlibrary)" ] && { | ||||
| 		case $(scwrypts.config.group ${__SCWRYPTS_GROUP_NAME} type) in | ||||
| 			( zsh ) | ||||
| 				[ -d "${scwryptsgrouproot}/lib" ] \ | ||||
| 					&& readonly ${scwryptsgroup}__zshlibrary="${scwryptsgrouproot}/lib" \ | ||||
| 					|| readonly ${scwryptsgroup}__zshlibrary="${scwryptsgrouproot}" \ | ||||
| 					; | ||||
| 				;; | ||||
| 			( '' ) | ||||
| 				[ -d "${scwryptsgrouproot}/zsh/lib" ] \ | ||||
| 					&& readonly ${scwryptsgroup}__zshlibrary="${scwryptsgrouproot}/zsh/lib" \ | ||||
| 					|| readonly ${scwryptsgroup}__zshlibrary="${scwryptsgrouproot}/zsh" \ | ||||
| 					; | ||||
| 				;; | ||||
| 		esac | ||||
| 	} | ||||
| done | ||||
| 
 | ||||
| [[ ${SCWRYPTS_GROUPS[1]} =~ ^scwrypts$ ]] \ | ||||
| 	|| utils.fail 69 "encountered error when loading essential group 'scwrypts'; aborting" | ||||
| 
 | ||||
| ##################################################################### | ||||
| ### cleanup ######################################################### | ||||
| ##################################################################### | ||||
| 
 | ||||
| unset __SCWRYPTS_ROOT  # you should now use '$(scwrypts.config.group scwrypts root)' | ||||
| 
 | ||||
| unset \ | ||||
| 	__SCWRYPTS_GROUP_LOADER __SCWRYPTS_GROUP_LOADERS __SCWRYPTS_GROUP_LOADER_REALPATH \ | ||||
| 	__SCWRYPTS_GROUP_DIR SCWRYPTS_GROUP_DIRS \ | ||||
| 	__SCWRYPTS_GROUP_NAME \ | ||||
| 	scwryptsgroup scwryptsgrouproot \ | ||||
| 	; | ||||
| 
 | ||||
| __SCWRYPT=1  # arbitrary; indicates currently inside a scwrypt | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| use db/postgres | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	echo.warning " \nthis function is in a beta state\n " | ||||
| 	WARNING " \nthis function is in a beta state\n " | ||||
| 	local _PASS _ARGS=() | ||||
| 	POSTGRES__SET_LOGIN_ARGS $@ | ||||
|  | ||||
| @@ -15,27 +15,27 @@ MAIN() { | ||||
| 	cd $SQL_DIR | ||||
|  | ||||
| 	[[ $(ls "*.sql" 2>&1 | wc -l) -eq 0 ]] && { | ||||
| 		echo.error "you haven't made any SQL commands yet" | ||||
| 		echo.reminder "add '.sql' files here: '$SQL_DIR/'" | ||||
| 		ERROR "you haven't made any SQL commands yet" | ||||
| 		REMINDER "add '.sql' files here: '$SQL_DIR/'" | ||||
| 		return 1 | ||||
| 	} | ||||
|  | ||||
| 	[ ! $INPUT_FILE ] && INPUT_FILE=$(utils.fzf 'select a sql file to run') | ||||
| 	[ ! $INPUT_FILE ] && user.abort | ||||
| 	[ ! $INPUT_FILE ] && INPUT_FILE=$(FZF 'select a sql file to run') | ||||
| 	[ ! $INPUT_FILE ] && ABORT | ||||
|  | ||||
| 	[ ! -f "$INPUT_FILE" ] && utils.fail 2 "no such sql file '$SQL_DIR/$INPUT_FILE'" | ||||
| 	[ ! -f "$INPUT_FILE" ] && FAIL 2 "no such sql file '$SQL_DIR/$INPUT_FILE'" | ||||
|  | ||||
| 	echo.status "loading '$INPUT_FILE' preview..." | ||||
| 	STATUS "loading '$INPUT_FILE' preview..." | ||||
| 	LESS "$INPUT_FILE" | ||||
|  | ||||
| 	echo.status "login   : $_USER@$_HOST:$_PORT/$_NAME" | ||||
| 	echo.status "command : '$INPUT_FILE'" | ||||
| 	STATUS "login   : $_USER@$_HOST:$_PORT/$_NAME" | ||||
| 	STATUS "command : '$INPUT_FILE'" | ||||
|  | ||||
| 	yN 'run this command?' || user.abort | ||||
| 	yN 'run this command?' || ABORT | ||||
|  | ||||
| 	echo.status "running '$INPUT_FILE'" | ||||
| 	STATUS "running '$INPUT_FILE'" | ||||
|  | ||||
| 	PSQL < $INPUT_FILE \ | ||||
| 		&& echo.success "finished running '$INPUT_FILE'" \ | ||||
| 		|| utils.fail 3 "something went wrong running '$INPUT_FILE' (see above)" | ||||
| 		&& SUCCESS "finished running '$INPUT_FILE'" \ | ||||
| 		|| FAIL 3 "something went wrong running '$INPUT_FILE' (see above)" | ||||
| } | ||||
|   | ||||
| @@ -1,29 +1,13 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| DEPENDENCIES+=(docker) | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	local RESOURCES=( | ||||
| 		container | ||||
| 		image | ||||
| 		volume | ||||
| 		system | ||||
| 		) | ||||
| 	WARNING 'this will prune all docker resources from the current machine' | ||||
| 	WARNING 'pruned resources are PERMANENTLY DELETED' | ||||
| 	yN 'continue?' || return 1 | ||||
|  | ||||
| 	echo.warning " | ||||
| 		this will prune the following docker resources from the | ||||
| 		current machine: | ||||
| 		   (${RESOURCES[@]}) | ||||
|  | ||||
| 		pruned resources are PERMANENTLY DELETED | ||||
| 	 " | ||||
|  | ||||
| 	utils.yN 'continue?' || utils.abort | ||||
|  | ||||
| 	echo.success "$( | ||||
| 		for RESOURCE in ${RESOURCES[@]} | ||||
| 		do | ||||
| 			echo "${RESOURCE}^:^$(docker ${RESOURCE} prune -f 2>/dev/null | tail -n 1)" | ||||
| 		done | column -ts '^' | ||||
| 	)" | ||||
| 	SUCCESS "CONTAINER : $(docker container prune -f 2>/dev/null | tail -n 1)" | ||||
| 	SUCCESS "IMAGE     : $(docker image prune -f 2>/dev/null | tail -n 1)" | ||||
| 	SUCCESS "VOLUME    : $(docker volume prune -f 2>/dev/null | tail -n 1)" | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| #!/usr/bin/env zsh | ||||
| #!/bin/zsh | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { | ||||
| 	echo.success 'Hello, World!' | ||||
| 	SUCCESS 'Hello, World!' | ||||
| } | ||||
|   | ||||
| @@ -1,13 +1,9 @@ | ||||
| #!/usr/bin/env zsh | ||||
| ##################################################################### | ||||
|  | ||||
| #!/bin/zsh | ||||
| use helm | ||||
|  | ||||
| use scwrypts | ||||
| ##################################################################### | ||||
|  | ||||
| helm.zshparse.usage | ||||
| helm.get-template.parse.usage | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { helm.get-template $@; } | ||||
| MAIN() { | ||||
| 	unset USAGE | ||||
| 	HELM__TEMPLATE__GET $@ | ||||
| } | ||||
|   | ||||
| @@ -1,135 +0,0 @@ | ||||
| ##################################################################### | ||||
| 
 | ||||
| use scwrypts/get-realpath | ||||
| 
 | ||||
| use helm/zshparse | ||||
| 
 | ||||
| DEPENDENCIES+=(helm) | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}() { | ||||
| 	local PARSERS=(helm.zshparse) | ||||
| 	eval "$(utils.parse.autosetup)" | ||||
| 
 | ||||
| 	########################################## | ||||
| 
 | ||||
| 	local HELM_LINT_ARGS=(${HELM_ARGS[@]}) | ||||
| 
 | ||||
| 	[[ ${USE_CHART_ROOT} =~ false ]] \ | ||||
| 		&& HELM_ARGS+=(--show-only "$(echo "${TEMPLATE_FILENAME}" | sed "s|^${CHART_ROOT}/||")") | ||||
| 
 | ||||
| 	local TEMPLATE_OUTPUT DEBUG_OUTPUT | ||||
| 	utils.io.capture TEMPLATE_OUTPUT DEBUG_OUTPUT \ | ||||
| 		helm template "${CHART_ROOT}" ${HELM_ARGS[@]} --debug \ | ||||
| 		; | ||||
| 
 | ||||
| 	local EXIT_CODE | ||||
| 	[ "${TEMPLATE_OUTPUT}" ] && EXIT_CODE=0 || EXIT_CODE=1 | ||||
| 
 | ||||
| 	case ${OUTPUT_MODE} in | ||||
| 		( raw ) | ||||
| 			[[ ${EXIT_CODE} -eq 0 ]] \ | ||||
| 				&& echo "${TEMPLATE_OUTPUT}" | grep -v '^# Source:.*$' \ | ||||
| 				|| echo "${DEBUG_OUTPUT}" >&2 \ | ||||
| 				; | ||||
| 			;; | ||||
| 
 | ||||
| 		( color ) | ||||
| 			[[ ${EXIT_CODE} -eq 0 ]] \ | ||||
| 				&& echo "${TEMPLATE_OUTPUT}" | bat --language yaml --color always \ | ||||
| 				|| echo "${DEBUG_OUTPUT}" >&2 \ | ||||
| 				; | ||||
| 			;; | ||||
| 
 | ||||
| 		( debug ) | ||||
| 			[[ ${EXIT_CODE} -eq 0 ]] \ | ||||
| 				&& KUBEVAL_RAW=$( | ||||
| 					echo "${TEMPLATE_OUTPUT}" \ | ||||
| 						| kubeval --schema-location https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master \ | ||||
| 					) \ | ||||
| 				|| KUBEVAL_RAW='no template output; kubeval skipped' | ||||
| 
 | ||||
| 			echo " | ||||
| 				${TEMPLATE_OUTPUT} | ||||
| 				--- | ||||
| 				debug: |\n$(echo ${DEBUG_OUTPUT} | sed 's/^/  /g') | ||||
| 
 | ||||
| 				kubeval: |\n$(echo ${KUBEVAL_RAW} | sed 's/^/  /g') | ||||
| 
 | ||||
| 				lint: |\n$(helm lint "${CHART_ROOT}" ${HELM_LINT_ARGS[@]} 2>&1 | sed 's/^/  /g') | ||||
| 				" | sed 's/^	\+//; 1d; $d' | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return ${EXIT_CODE} | ||||
| } | ||||
| 
 | ||||
| ##################################################################### | ||||
| 
 | ||||
| ${scwryptsmodule}.parse() { | ||||
| 	local PARSED=0 | ||||
| 
 | ||||
| 	case $1 in | ||||
| 		( --colorize ) PARSED=1; OUTPUT_MODE=color ;; | ||||
| 		( --raw      ) PARSED=1; OUTPUT_MODE=raw ;; | ||||
| 		( --debug    ) PARSED=1; OUTPUT_MODE=debug ;; | ||||
| 
 | ||||
| 		( --update   ) PARSED=1; UPDATE_DEPENDENCIES=true ;; | ||||
| 	esac | ||||
| 
 | ||||
| 	return ${PARSED} | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.locals() { | ||||
| 	local OUTPUT_MODE=default | ||||
| 	local UPDATE_DEPENDENCIES=false | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.usage() { | ||||
| 	USAGE__description=" | ||||
| 		Smart helm-template generator which auto-detects the chart | ||||
| 		and sample values for testing and developing helm charts. | ||||
| 	" | ||||
| 
 | ||||
| 	local DEFAULT | ||||
| 	utils.dependencies.check bat &>/dev/null \ | ||||
| 		&& DEFAULT=color || DEFAULT=raw | ||||
| 
 | ||||
| 	USAGE__options+=" | ||||
| 		--colorize   $([[ ${DEFAULT} =~ color ]] && printf '(default) ')use 'bat' to colorize output | ||||
| 		--raw        $([[ ${DEFAULT} =~ raw   ]] && printf '(default) ')remove scwrypts-added fluff and only output helm template details | ||||
| 		--debug      debug template with kubeval and helm-lint | ||||
| 
 | ||||
| 		--update   update dependencies before generating template output | ||||
| 	" | ||||
| } | ||||
| 
 | ||||
| ${scwryptsmodule}.parse.validate() { | ||||
| 	case ${OUTPUT_MODE} in | ||||
| 		( default ) | ||||
| 			utils.dependencies.check bat &>/dev/null \ | ||||
| 				&& OUTPUT_MODE=color \ | ||||
| 				|| OUTPUT_MODE=raw \ | ||||
| 				; | ||||
| 			;; | ||||
| 
 | ||||
| 		( color ) | ||||
| 			utils.dependencies.check bat || ((ERRORS+=1)) | ||||
| 			;; | ||||
| 
 | ||||
| 		( debug ) | ||||
| 			utils.dependencies.check kubeval \ | ||||
| 				|| echo.error 'kubeval is required for --debug' | ||||
| 			;; | ||||
| 	esac | ||||
| 
 | ||||
| 	case ${UPDATE_DEPENDENCIES} in | ||||
| 		( false ) ;; | ||||
| 		( true ) | ||||
| 			use helm/update-dependencies | ||||
| 			helm.update-dependencies --template-filename "${TEMPLATE_FILENAME}" &>/dev/null \ | ||||
| 				|| echo.error 'failed to update dependencies' | ||||
| 			;; | ||||
| 	esac | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| # | ||||
| # helm template testing and generation helpers | ||||
| # | ||||
| 
 | ||||
| 
 | ||||
| # ensures default values are injected from local Chart dependencies | ||||
| use helm/update-dependencies | ||||
| 
 | ||||
| 
 | ||||
| # template generation | ||||
| use helm/get-template | ||||
| 
 | ||||
| 
 | ||||
| # shared argument parser | ||||
| use helm/zshparse | ||||
| @@ -1,13 +1,9 @@ | ||||
| #!/usr/bin/env zsh | ||||
| ##################################################################### | ||||
|  | ||||
| #!/bin/zsh | ||||
| use helm | ||||
|  | ||||
| use scwrypts | ||||
| ##################################################################### | ||||
|  | ||||
| helm.zshparse.usage | ||||
| helm.update-dependencies.parse.usage | ||||
|  | ||||
| ##################################################################### | ||||
|  | ||||
| MAIN() { helm.update-dependencies $@; } | ||||
| MAIN() { | ||||
| 	unset USAGE | ||||
| 	HELM__DEPENDENCY__UPDATE $@ | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user