Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .claude/skills/linting-code/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
name: linting-code
description: >
Lints shell scripts and Markdown files in the bash-logger repository using the project's
configured toolchain. Use this skill whenever checking code quality, fixing linting errors,
or running lint as part of a pre-commit or pre-PR workflow.
---

# Linting Code

## Tools and where configuration lives

| Tool | Checks | Config |
| --- | --- | --- |
| ShellCheck | Shell syntax, quoting, portability, common bugs | `.pre-commit-config.yaml` (args: `--severity=warning --external-sources`) |
| MarkdownLint | Markdown formatting, list style, line length | `.markdownlint.yaml` |

Both run through `pre-commit` so versions are pinned. Always use the Make targets or `pre-commit` directly — do not invoke `shellcheck` or `markdownlint` as standalone commands.

## Commands

### Lint everything (shell + Markdown)

```bash
make lint
```

### Shell scripts only

```bash
make lint-shell
```

### Markdown only

```bash
make lint-markdown
```

### Run all pre-commit hooks including tests

```bash
make pre-commit
```

### Run a single hook by name

```bash
pre-commit run shellcheck --all-files
pre-commit run markdownlint --all-files
```

## Key rules — write clean code from the start

### Shell scripts

* 4-space indentation, no tabs
* Lines ≤ 100 characters
* Quote all variable expansions: `"$var"` not `$var`
* `[[ ]]` for bash conditionals; `[ ]` only when POSIX portability is needed
* `$(...)` not backticks
* `UPPERCASE` for constants/exported vars; `lowercase` for locals and functions
* When suppressing a ShellCheck warning, add an explanation comment:

```bash
# shellcheck disable=SC3010 -- bash-specific syntax required for performance here
```

### Markdown

* Unordered list markers: `*` only — **never** `-` (MD004)
* 2-space list indentation (MD007)
* Maximum line length: 200 characters; code blocks and tables are exempt (MD013)
* Blank line above and below every heading (MD022)
* Ordered lists: use `1.` for every item, or true sequential numbers; never an arbitrary
starting number (MD029)
* Table separator rows: always `| --- | --- |`, **never** `|---|---|` — MD060 compact style
requires a space to the left and right of every `---` cell (MD060)
* Specify a language on all fenced code blocks where possible (optional but preferred)

## Interpreting failures

### ShellCheck

Format: `file.sh:LINE:COL: severity: message [SCXXX]`

Look up unknown codes at `https://www.shellcheck.net/wiki/SCXXX`.

Most common codes in this project:

| Code | Cause | Fix |
| --- | --- | --- |
| SC2086 | Unquoted variable | Wrap in `"$var"` |
| SC2155 | Combined `local`/assign | Split: `local x; x=$(...)` |
| SC2181 | Check `$?` instead of direct `if` | Use `if command; then` directly |

### MarkdownLint

MarkdownLint runs with `--fix` — most formatting issues auto-correct in-place. After auto-fix, pre-commit fails the hook and you must `git add` the modified files before re-running. Violations
that cannot be auto-fixed (long lines, wrong list markers) require manual edits.
103 changes: 103 additions & 0 deletions .claude/skills/pre-pr-checks/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
name: pre-pr-checks
description: >
Runs the full gate sequence before raising a pull request on bash-logger. Covers linting,
targeted tests, full test suite, code review checklist, commit message audit, PR description
requirements, and branch hygiene. Use this skill before pushing to a shared branch or opening
a PR.
---

# Pre-PR Checks

Work through these steps in order. Each builds on the last.

## 1. Lint

```bash
make lint
```

Fix all ShellCheck and MarkdownLint failures. MarkdownLint auto-fixes most issues in-place, but does not re-stage the files — run `git add` on any modified files and re-run `make lint` before
continuing.

## 2. Targeted tests

Identify relevant suites (see `running-tests` skill) and run them:

```bash
./tests/run_tests.sh <suite_name>
```

All must pass before continuing.

## 3. Full test suite

```bash
./tests/run_tests.sh
```

Zero failures required. Investigate all regressions before pushing.

## 4. Code review checklist

### Shell scripts (`logging.sh`, `install.sh`, scripts)

* [ ] Every exit path assigns the correct return/exit code — passing tests do not guarantee all exit paths are correct
* [ ] Variables quoted throughout: `"$var"`
* [ ] No hardcoded paths that break portability
* [ ] New functions have comments explaining purpose and parameters
* [ ] Shell-agnostic where possible; bash-specific constructs commented with ShellCheck suppressions
* [ ] Lines ≤ 100 characters
* [ ] No leftover debug `echo` or `set -x` calls

### Test files

* [ ] Every new test function called at the bottom of its suite file
* [ ] `|| return` follows every assertion
* [ ] All I/O uses `$TEST_DIR`

### Documentation

* [ ] New flags, functions, or behaviour documented in the relevant `.md` file
* [ ] If `logging.sh` public API changed, `README.md` and `docs/` updated
* [ ] Markdown uses `*` list markers, 2-space indent, ≤ 200 char lines

## 5. Commit message audit

```bash
git log origin/main..HEAD --oneline
```

Every commit must follow `<type>(<scope>): <subject>` format. Amend any that do not:

```bash
git rebase -i origin/main # reword the offending commits
```

If a commit addresses a tracked issue, confirm `Fixes #NNN` or `Refs #NNN` is in the footer. See the `writing-commits` skill for the full specification.

## 6. PR description

* Title: `<type>(<scope>): <subject>` matching the primary intent of the PR
* Body must include: summary, list of changes, testing steps taken, and issue links
* All related issues linked — at minimum the issue that prompted the work

## 7. Branch hygiene

```bash
git fetch origin
git rebase origin/main
```

Resolve conflicts, then re-run the full test suite.

## Quick-reference: common pre-PR failures

| Symptom | Cause | Fix |
| --- | --- | --- |
| ShellCheck SC2086 | Unquoted variable | `"$var"` |
| ShellCheck SC2155 | Combined declare/assign | `local x; x=$(...)` |
| MarkdownLint MD004 | List marker is `-` | Change to `*` |
| Test not run | Call missing at bottom of suite | Add the call |
| Assertion not reached | Missing `\|\| return` on prior assertion | Add `\|\| return` |
| No release triggered | Commit type not release-triggering | Check `.releaserc.json` |
114 changes: 114 additions & 0 deletions .claude/skills/running-tests/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
name: running-tests
description: >
Runs the bash-logger test suite — either the full suite or a targeted subset. Use this skill
whenever running, selecting, or interpreting tests in this repository. Covers discovering
available suites, choosing which to run after a change, correct invocation syntax, and reading
test output.
---

# Running Tests

## Discover available suites first

Never assume which suites exist. Always discover them at runtime:

```bash
ls tests/test_*.sh | grep -v test_example.sh | grep -v test_helpers.sh | sed 's|tests/||; s|\.sh||'
```

This lists every runnable suite name. `test_example.sh` is a contributor template and `test_helpers.sh` is a shared library — neither is a runnable suite.

## Choosing: targeted vs full suite

Default to targeted. Only run the full suite for broad changes or as a pre-PR gate.

| What changed | Run |
| --- | --- |
| A specific functional area (e.g. format handling, log levels) | The matching suite(s) only |
| `logging.sh` core logic (init, output routing, sanitization) | Full suite |
| `install.sh` | `test_install` only |
| Config file parsing | `test_config` and `test_config_security` |
| Security-related code | Relevant security suites + full suite |
| New test file added | New suite only, then full suite |
| Pre-PR / CI gate | Full suite |

### Mapping changed code to suites

After discovering available suites, match by name:

* `logging.sh` format/template changes → `test_format`
* `logging.sh` level logic → `test_log_levels`
* `logging.sh` initialisation → `test_initialization`
* `logging.sh` output/stream routing → `test_output`
* Config file support → `test_config`, `test_config_security`, `test_runtime_config`
* Journal integration → `test_journal_logging`
* Sanitisation (ANSI, newlines, paths) → `test_ansi_injection`, `test_unsafe_newlines`, `test_path_traversal`, `test_script_name_sanitization`
* Security hardening → `test_environment_security`, `test_sensitive_data`, `test_config_security`, `test_toctou_protection`
* `install.sh` → `test_install`
* JUnit/CI reporting → `test_junit_output`

When in doubt about scope, run the full suite.

## Commands

### Full suite

```bash
./tests/run_tests.sh
```

Or via Make (quieter output):

```bash
make test
```

### Single suite

```bash
./tests/run_tests.sh <suite_name>
```

`<suite_name>` is the filename without the `test_` prefix **and** without `.sh`:

```bash
# Correct
./tests/run_tests.sh log_levels
./tests/run_tests.sh config
./tests/run_tests.sh initialization

# Also accepted — runner strips the extension
./tests/run_tests.sh test_log_levels.sh
```

### Multiple suites in one invocation

```bash
./tests/run_tests.sh config config_security runtime_config
```

### JUnit XML output (for CI artefacts)

```bash
make test-junit
```

## Reading output

```
✓ (green) — passed
✗ (red) — failed; expected/actual values printed below
⊘ (yellow) — skipped (e.g. a zsh-only test running under bash)
```

Summary line: `Total Tests: N Passed: N Failed: N Skipped: N`

Exit code `0` = all passed. Exit code `1` = at least one failure. Fix all failures before committing.

## Mistakes to avoid

* Do **not** run from inside the `tests/` directory — always run from repo root.
* Do **not** pass the full path (`tests/test_config.sh`) — pass the suite name only.
* Do **not** skip the discovery step and guess suite names — the list changes as the project grows.
* `test_helpers.sh` and `test_example.sh` are never valid suite arguments.
Loading
Loading