9.3 KiB
Contributing Guidelines
Welcome!
Thank you for considering contributing to this project's development and/or documentation. Just a reminder: if you're new to this project or to OSS and want to find issues to work on, please check the following labels on issues:
To see all labels and their meanings, check this wiki page.
Table of contents
- Contributing Guidelines
Quick links
- Gitter channel →: Feel free to come chat with us on Gitter
- README →
- Code of conduct →
- License information →
- Original repository →
- Issues →
- Pull requests →
- Milestones →
- Projects →
Code of conduct
Harassment or rudeness of any kind will not be tolerated, period. For specifics, see the CODE_OF_CONDUCT file.
Asking questions
Please check the documentation or existing discussions and issues first.
If you cannot find an answer to your question, please feel free to hop on our
Gitter.
Updating documentation
We love documentation and people who love documentation!
If you love writing clear, accessible docs, please don't be shy about pull requests. Remember: docs are just as important as code.
Also: no typo is too small to fix! Really. Of course, batches of fixes are preferred, but even one nit is one nit too many.
Testing
To run all tests:
bin/bats test
To run a single test file:
bin/bats test/file.bats
When running from a terminal, Bats uses the pretty formatter by default.
However, to debug Bats you might need to see the raw test output.
The cat formatter is intended as an internal debugging tool because
it does not process test outputs.
To use it, run Bats with the --formatter cat option.
Coding conventions
Use (shfmt)[https://github.com/mvdan/sh#shfmt] and ShellCheck. The CI will enforce this.
Use snake_case for all identifiers.
Function declarations
- 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
Variable and parameter declarations
- 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:]]/}" ]] }
Command substitution
- 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 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.
Process substitution
- 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.
Conditionals and loops
- 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.
Generating output
- 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.
Signal names
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'
success
Credits
The official bash logo is copyrighted by the Free Software Foundation, 2016 under the Free Art License
This guide borrows heavily from @mbland's go-script-bash (with some sections directly quoted), which in turn was drafted with tips from Wrangling Web Contributions: How to Build a CONTRIBUTING.md and with some inspiration from the Atom project's CONTRIBUTING.md file.