===================================================================== Excited to bring V5 to life. This includes some BREAKING CHANGES to several aspects of ZSH-type scwrypts. Please refer to the readme for upgrade details (specifically docs/upgrade/v4-to-v5.md) --- New Features ------------------------- - ZSH testing library with basic mock capabilities - new scwrypts environment file format includes metadata and more advanced features like optional parent env overrides, selection inheritence, and improved structurual flexibility - speedup cache for non-CI runs of ZSH-type scwrypts - ${scwryptsmodule} syntax now allows a consistent unique-naming scheme for functions in ZSH-type scwrypts while providing better insight into origin of API calls in other modules - reusable, case-statement-driven argument parsers in ZSH-type scwrypts --- Changes ------------------------------ - several utility function renames in ZSH-type scwrypts to improve consistency - documentation comments included in ZSH libraries - ZSH-type scwrypts now allow library modules to live alongside executables (zsh/lib still supported; autodetection determines default) --- Bug Fixes ---------------------------- - hardened environment checking for REQUIRED_ENV variables; this removes the ability to overwrite variables in local function contexts
ZSH Scwrypts
Since they emulate direct user interaction, shell scripts are a (commonly dreaded) go-to for 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.
The Basic Framework
Take a look at the simplest ZSH-type scwrypt: hello-world. The bare minimum API for ZSH-type scwrypts is to:
- include the shebang
#!/usr/bin/env zsh
on the first line of the file - wrap your zsh in a function called
MAIN()
- 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
:
{"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, 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 theERRORS
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:
#!/usr/bin/env zsh
use cloud/aws
#####################################################################
MAIN() {
cloud.aws sts get-caller-identity
}