Problem
Tag selection is weaker than the systems people migrate from.
--tag is repeatable but OR-only (bashunit test --help: "repeatable, OR logic"). There is no way to say "slow and db".
- There is no negation inside an expression;
--exclude-tag is a separate flag that always wins.
- Tags are per function only.
src/helper/tags.sh:10 build_tags_map scans the contiguous comment block directly above each function definition, so tagging a whole file means repeating # @tag integration above every test in it.
bats-core supports --filter-tags 'a,!b' with AND semantics and has both # bats test_tags= and # bats file_tags=.
Proposal
File-level tags — a # @tags <list> comment before the first function definition (or anywhere at top level) applies to every test in that file, unioned with per-function # @tag.
Tag expressions in --tag:
--tag slow # has slow (unchanged)
--tag slow --tag db # slow OR db (unchanged, back-compat)
--tag 'slow&&db' # slow AND db
--tag '!slow' # NOT slow
--tag 'db&&!slow' # db AND NOT slow
Precedence stays as documented: --exclude-tag still wins over any --tag match.
Where to change
src/helper/tags.sh:10 build_tags_map — single awk pass; extend it to also collect file-level tags and union them in.
src/helper/tags.sh:99 function_matches_tags — the expression evaluator lives here.
src/helper/tags.sh:74 tags_for_function.
Acceptance criteria
Repo checklist (agent)
- TDD: RED → GREEN → REFACTOR. Write the failing test first.
- Bash 3.0+ only: no
printf -v, no += append, no declare -A, no [[ ]], no ${var,,}, no &>>, no ${arr[-1]}. Expanding a possibly-empty array under set -u needs ${arr[@]+"${arr[@]}"}.
- A new CLI flag must be wired in all of these or a parity test fails:
- Gates:
make sa, make lint, ./bashunit tests/, ./bashunit --parallel tests/. Never run shfmt -w.
- Docs: update
docs/command-line.md. Editing docs/assertions.md invalidates the bashunit doc acceptance snapshot — regenerate it.
- CHANGELOG.md: add one line under
## Unreleased.
- Fixtures under
tests/acceptance/fixtures/ must not end in *test.sh.
- One issue = one PR.
Problem
Tag selection is weaker than the systems people migrate from.
--tagis repeatable but OR-only (bashunit test --help: "repeatable, OR logic"). There is no way to say "slow and db".--exclude-tagis a separate flag that always wins.src/helper/tags.sh:10build_tags_mapscans the contiguous comment block directly above eachfunctiondefinition, so tagging a whole file means repeating# @tag integrationabove every test in it.bats-core supports
--filter-tags 'a,!b'with AND semantics and has both# bats test_tags=and# bats file_tags=.Proposal
File-level tags — a
# @tags <list>comment before the first function definition (or anywhere at top level) applies to every test in that file, unioned with per-function# @tag.Tag expressions in
--tag:Precedence stays as documented:
--exclude-tagstill wins over any--tagmatch.Where to change
src/helper/tags.sh:10build_tags_map— single awk pass; extend it to also collect file-level tags and union them in.src/helper/tags.sh:99function_matches_tags— the expression evaluator lives here.src/helper/tags.sh:74tags_for_function.Acceptance criteria
# @tags a babove the first function applies both tags to every test in the file--tag 'a&&b'selects only tests carrying both--tag '!a'selects only tests withouta--tag 'a&&!b'works--tagflags keep OR semantics between them (no behaviour change for existing users)--exclude-tagstill wins over an expression match'a&&','&&','!') exits non-zero with a usage error, not a silent full-suite run (Unknown options are silently ignored: a typo'd flag runs a different suite and exits 0 #871 class of bug)build_tags_mapstill holds — no per-function rescan (perf(tags): build per-file function-to-tags map in one pass instead of per-function grep/sed walk #773)tests/unit/helper/tags_test.sh, acceptance coverage for the CLI surfaceRepo checklist (agent)
printf -v, no+=append, nodeclare -A, no[[ ]], no${var,,}, no&>>, no${arr[-1]}. Expanding a possibly-empty array underset -uneeds${arr[@]+"${arr[@]}"}.src/main/test.sh(report-style flags needexport -n, seesrc/main/test.sh:188-196for why)bashunit::main::validate_config_or_exit(src/main/validate.sh:60) — unvalidated input used to run the wrong thing and exit 0 (Unknown options are silently ignored: a typo'd flag runs a different suite and exits 0 #871, --jobs with a non-integer value hangs on Bash 3.x and is silently ignored on Bash 4.3+ #873)src/config/env.shand a documented line in.env.example--helptext in the same block it belongs tocompletions/bashunit.bashandcompletions/_bashunit(anti-drift test feat(cli): bash and zsh completion scripts with an anti-drift test #778 fails otherwise)make sa,make lint,./bashunit tests/,./bashunit --parallel tests/. Never runshfmt -w.docs/command-line.md. Editingdocs/assertions.mdinvalidates thebashunit docacceptance snapshot — regenerate it.## Unreleased.tests/acceptance/fixtures/must not end in*test.sh.