Skip to content

rafaelvieiras/boatman

Repository files navigation

boatman banner

boatman

License: MIT

boatman is a zero-dependency CLI that installs a smart quality gate with a ratchet mechanism into any JavaScript or TypeScript project. It detects your stack automatically, presents the viable options, and generates the necessary files: a standalone gate script, a CI workflow, and npm scripts — all tailored to your project.


How the Ratchet Works

A ratchet only moves in one direction. The quality gate works the same way:

  1. Baseline — You generate a baseline.json that records the current metrics of your project (coverage percentage, lint error count, duplication rate, vulnerability count).
  2. Every PR/push — The gate compares current metrics against the baseline.
  3. Regression = blocked — If a metric got worse (e.g. coverage dropped, more lint errors), the CI job fails and the PR cannot be merged.
  4. Improvement = recorded — If metrics improved, the gate reports it. You run quality:baseline to advance the ratchet to the new, better state.

The key insight: you can never silently regress. Every merge either holds the line or improves it.


Quick Start

npx boatman init

Or target a specific directory:

npx boatman init --path ./my-project

Accept all defaults without interactive prompts:

npx boatman --yes

Preview what would be generated without writing any files:

npx boatman --dry-run

Supported Stack

Category Supported
Language JavaScript, TypeScript
Package manager npm, pnpm, yarn, bun
Test runner Vitest, Jest, Mocha
Coverage @vitest/coverage-v8, @vitest/coverage-istanbul, jest
Linter ESLint (any config format)
Mutation testing Stryker (@stryker-mutator/core)
CI platform GitHub Actions, GitLab CI

Available Checks

Check What it tracks Blocking?
eslint Error and warning count Warn only (non-blocking)
coverage Lines, branches, functions percentage Yes — drop blocks the PR
duplication Code duplication percentage (via jscpd) Yes — increase blocks the PR
audit Critical and high npm vulnerabilities Critical: zero-tolerance
mutation Mutation score percentage (via Stryker) Warn only (non-blocking)
complexity Cyclomatic complexity & long functions Warn only (non-blocking)
pr-comment Posts a Markdown report as a PR comment N/A (GitHub only)

Generated Files

After running boatman init, the following files are created or updated in your project:

your-project/
├── scripts/
│   ├── quality-gate.mjs          # Standalone gate script
│   └── count-lint.mjs            # ESLint output counter (stdin helper)
├── .github/
│   └── workflows/
│       └── quality-gate.yml      # GitHub Actions workflow (if selected)
├── .gitlab-ci.yml                # GitLab CI config (if selected)
└── package.json                  # Scripts injected: quality:gate, quality:baseline, ...

Injected npm scripts

Script What it does
quality:gate Runs the gate in CI mode (Markdown output)
quality:gate:local Runs the gate with human-readable terminal output
quality:baseline Runs all tools and saves a new baseline.json
duplication Runs jscpd and saves report (if selected)
quality:mutation Runs Stryker mutation tests (if selected)

Using count-lint

count-lint.mjs is a helper that reads ESLint's JSON output from stdin and prints a human-readable summary. Useful for quick checks without opening the full JSON report:

npx eslint src --ext ts,tsx --format json | node scripts/count-lint.mjs
# ESLint: 3 errors, 12 warnings

Complexity Check

When the complexity check is enabled, boatman runs an ESLint scan with two specific rules applied on top of your existing config:

Rule Default threshold Metric tracked
complexity max 10 complexity_violations
max-lines-per-function max 50 lines long_function_violations

The scan writes its output to reports/complexity.json and the gate tracks the number of violations over time. Both metrics are non-blocking — they warn when the count increases but do not fail the build. This lets teams adopt the check incrementally: start tracking today, reduce the count gradually, and never let it grow again.

The check requires ESLint to be installed in the target project. It is available in the interactive installer only when ESLint is detected, and defaults to off (opt-in).


Using the Baseline

1. Generate the initial baseline

After installation, run the tools once to create your starting point:

npm run quality:baseline
# or: pnpm quality:baseline / yarn quality:baseline / bun run quality:baseline

This runs ESLint, your test suite with coverage, jscpd, npm audit, Stryker, and/or the complexity scan — then saves all metric values to baseline.json:

{
  "generatedAt": "2026-05-07T10:00:00.000Z",
  "commit": "a1b2c3d",
  "project": "my-project",
  "metrics": {
    "eslint_errors": 0,
    "coverage_lines": 84.2,
    "duplicate_percent": 3.2,
    "audit_critical": 0,
    "mutation_score": 65.3,
    "complexity_violations": 2,
    "long_function_violations": 5
  }
}

2. Commit the baseline

git add baseline.json
git commit -m "chore: add quality gate baseline"

The baseline is tracked in version control so every branch has the same reference point.

3. Advance the ratchet when you improve

After a PR that genuinely improved metrics (e.g. added tests, fixed lint errors), update the baseline:

npm run quality:baseline
git add baseline.json
git commit -m "chore: advance quality baseline after coverage improvements"

Running Locally

npm run quality:gate:local

Example output:

Quality Gate — my-project

Improvements:
  ✔ Coverage lines %: 84.2 %  (was 80.1 %  +4.10 ↑)
  ✔ Mutation score:   65.3 %  (was 60.0 %  +5.30 ↑)

Unchanged:
  ─ ESLint errors: 0 errors
  ─ Duplication %: 3.2 %

Quality gate PASSED.

How it Looks in CI (PR Comment)

When running on GitHub Actions with the pr-comment check enabled, the gate posts a sticky comment on every PR:

## ✅ Quality Gate PASSED

**Project:** `my-project`
**Generated:** 2026-05-07T10:00:00.000Z

### Metrics

| Metric              | Current  | Baseline | Delta   | Status |
|---------------------|----------|----------|---------|--------|
| ESLint errors       | 0 errors | 0 errors | +0.00 → | ➡️     |
| Coverage lines %    | 84.2 %   | 80.1 %   | +4.10 ↑ | ✅     |
| Coverage branches % | 78.5 %   | 78.5 %   | +0.00 → | ➡️     |
| Duplication %       | 3.2 %    | 3.5 %    | -0.30 ↓ | ✅     |
| Mutation score      | 65.3 %   | 60.0 %   | +5.30 ↑ | ✅     |

### ✅ Improvements Detected

- **Coverage lines %**: 84.2 % ↑ (was 80.1 %)
- **Duplication %**: 3.2 % (was 3.5 %)
- **Mutation score**: 65.3 % ↑ (was 60.0 %)

> Run `npm run quality:baseline` to update the baseline with these improvements.

---
*Generated by [boatman](https://github.com/rafaelvieiras/boatman)*

When a regression is detected:

## ❌ Quality Gate FAILED

### ❌ Blocking Regressions

- **Coverage lines %**: 72.3 % ← was 80.1 %

> Fix these regressions before merging, then run `npm run quality:baseline` if the new values are intentional.

Zero Dependencies

boatman uses only Node.js built-ins (fs, path, readline, child_process). The generated gate script is also standalone — it does not import anything from boatman at runtime.


Contributing

  1. Fork the repository
  2. Create your feature branch: git checkout -b feat/my-feature
  3. Make your changes and ensure the CLI still works: node bin/boatman.mjs --dry-run
  4. Commit your changes: git commit -m "feat: add my feature"
  5. Open a pull request

Bug reports and feature requests are welcome via GitHub Issues.


License

MIT — see LICENSE for details.

About

boatman is a zero-dependency CLI smart quality gate with a ratchet mechanism for Humans and AI.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors