Thanks for thinking about helping us!
After cloning the repository, then you'll want to bootstrap your system:
script/bootstrapThis will ensure your system has all the programs needed to test everything.
To run all lint checks:
script/lintTo run all tests:
script/testTo run all Bats tests:
bats testsTo run specific Bats tests:
bats tests/<file>.batsThese coding conventions were initially copied from bats-core's coding conventions, but I expect them to diverge over time.
Use shfmt and ShellCheck. The CI will enforce this.
Use snake_case for all identifiers.
- Declare functions without the
functionkeyword. - Strive to always use
return, neverexit, unless an error condition is severe enough to warrant it.- Calling
exitmakes it difficult for the caller to recover from an error, or to compose new commands from existing ones.
- Calling
- Declare all variables inside functions using
local. - Declare temporary file-level variables using
declare. Useunsetto remove them when finished. - Don't use
local -r, as a readonly local variable in one scope can cause a conflict when it calls a function that declares alocalvariable of the same name. - Don't use type flags with
declareorlocal. Assignments to integer variables in particular may behave differently, and it has no effect on array variables. - For most functions, the first lines should use
localdeclarations to assign the original positional parameters to more meaningful names, e.g.:For very short functions, this may not be necessary, e.g.:format_summary() { local cmd_name="$1" local summary="$2" local longest_name_len="$3"
has_spaces() { [[ "$1" != "${1//[[:space:]]/}" ]] }
- If possible, don't. While this capability is one of Bash's core strengths, every new process created by Bats makes the framework slower, and speed is critical to encouraging the practice of automated testing. (This is especially true on Windows, where process creation is one or two orders of magnitude slower. See https://github.com/bats-core/bats-core#8 for an illustration of the difference avoiding subshells makes.) Bash is quite powerful; see if you can do what you need in pure Bash first.
- If you need to capture the output from a function, store the output using
printf -vinstead if possible.-vspecifies the name of the variable into which to write the result; the caller can supply this name as a parameter. - If you must use command substitution, use
$()instead of backticks, as it's more robust, more searchable, and can be nested.
- If possible, don't use it. See the advice on avoiding subprocesses and using
printf -vin the Command substitution section above. - Use wherever necessary and possible, such as when piping input into a
whileloop (which avoids having the loop body execute in a subshell) or running a command taking multiple filename arguments based on output from a function or pipeline (e.g.diff). - Warning: It is impossible to directly determine the exit status of a process substitution; emitting an exit status as the last line of output is a possible workaround.
- Always use
[[and]]for evaluating variables. Per the guideline under Formatting, quote variables and strings within the brackets, but not regular expressions (or variables containing regular expressions) appearing on the right side of the=~operator.
- Use
printfinstead ofecho. Both are Bash builtins, and there's no perceptible performance difference when running Bats under thetimebuiltin. However,printfprovides a more consistent experience in general, asechohas limitations to the arguments it accepts, and even the same version of Bash may produce different results forechobased on how the binary was compiled. See Stack Overflow: Why is printf better than echo? for excruciating details.
Always use upper case signal names (e.g. trap - INT EXIT) to avoid locale
dependent errors. In some locales (for example Turkish, see
Turkish dotless i) lower
case signal names cause Bash to error. An example of the problem:
$ echo "tr_TR.UTF-8 UTF-8" >> /etc/locale.gen && locale-gen tr_TR.UTF-8 # Ubuntu derivatives
$ LC_CTYPE=tr_TR.UTF-8 LC_MESSAGES=C bash -c 'trap - int && echo success'
bash: line 0: trap: int: invalid signal specification
$ LC_CTYPE=tr_TR.UTF-8 LC_MESSAGES=C bash -c 'trap - INT && echo success'
successThis project uses several tools to ensure high quality: