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
29 changes: 0 additions & 29 deletions .claude/CLAUDE.md

This file was deleted.

18 changes: 18 additions & 0 deletions .claude/rules/adr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
paths: "docs/adr/**"
---

# Writing an ADR

Before writing, fixing or reviewing a record in `docs/adr/`, read
`docs/adr/README.md` and follow "How to write one" step by step. It is the whole
rule; this file only makes sure it is read at the moment of writing.

The three steps people skip:

- Write the title first, as one sentence. It is the decision; everything else
restates it or follows from it.
- Ask of every line: would changing this take a new record that supersedes this
one? If an ordinary change would do, the line is specification — leave it out.
- When fixing a record, rewrite it from the title. Do not edit the previous
draft.
2 changes: 1 addition & 1 deletion .claude/rules/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Project-specific rules for the Probitas Packages monorepo.
BEFORE reporting task completion, run and ensure zero errors/warnings:

```bash
bun run verify
just ci
```

## Commit Conventions
Expand Down
20 changes: 20 additions & 0 deletions .claude/rules/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
paths: "docs/spec/**"
---

# Writing a spec

Before writing, fixing or reviewing a file in `docs/spec/`, read
`docs/spec/README.md` and follow "How to write one". It is the whole rule; this
file only makes sure it is read at the moment of writing.

The checks people skip:

- Ask of every line: can a test pin this down? Then it belongs in a test. Would
a user call a change to it a change in behaviour? If not, it is not spec.
- Numbered steps, mapping tables, other programs' file locations, exact strings
and ordering rules are candidates to take out — unless they describe a format
this project defines for others to write.
- A review fix that does not change what a user sees does not touch the spec.
- Do not copy the level of detail of neighbouring specs; they may be too
detailed themselves.
1 change: 1 addition & 0 deletions .envrc.sample
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# Copy to .envrc and run `direnv allow` to enter the Nix dev shell automatically.
use flake
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Check text out with LF on every OS, so a Windows checkout builds and tests
# the same bytes as the others.
* text=auto eol=lf
42 changes: 26 additions & 16 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ on:
workflow_dispatch:

permissions:
contents: write # attach versions.json and edit the release notes
id-token: write # npm trusted publishing and JSR OIDC
contents: read

concurrency:
group: publish
Expand All @@ -33,6 +32,9 @@ jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: write # attach versions.json and edit the release notes
id-token: write # npm trusted publishing and JSR OIDC
env:
GH_TOKEN: ${{ github.token }}
steps:
Expand All @@ -43,13 +45,16 @@ jobs:
echo "NOTES=$RUNNER_TEMP/notes.md"
} >> "$GITHUB_ENV"

- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0 # the plan compares against the previous release tag
persist-credentials: false

- uses: nixbuild/nix-quick-install-action@v34
- run: nix develop -c bun install --frozen-lockfile
- run: nix develop -c bun run check
- uses: nixbuild/nix-quick-install-action@v35
# Load the development shell (flake.nix) into the job.
- uses: nicknovitski/nix-develop@v1
- run: just install
- run: just typecheck

- name: Decide what to publish
id: mode
Expand Down Expand Up @@ -92,10 +97,10 @@ jobs:
echo "Reusing the plan attached to $TAG"
exit 0
fi
nix develop -c bun scripts/release_plan.ts --tag "$TAG" --previous "$PREVIOUS" \
bun scripts/release_plan.ts --tag "$TAG" --previous "$PREVIOUS" \
--out "$PLAN" --notes "$NOTES"
if [ "$EVENT" = "release" ]; then
gh release upload "$TAG" "$PLAN"
gh release upload "$TAG" "$PLAN" --clobber
gh release view "$TAG" --json body --jq .body > "$RUNNER_TEMP/body.md"
printf '\n\n' >> "$RUNNER_TEMP/body.md"
cat "$NOTES" >> "$RUNNER_TEMP/body.md"
Expand All @@ -104,17 +109,20 @@ jobs:

- name: Apply versions
if: steps.mode.outputs.dry-run != 'true'
env:
DIST_TAG: ${{ steps.mode.outputs.dist-tag }}
RUN_NUMBER: ${{ github.run_number }}
run: |
if [ "${{ steps.mode.outputs.dist-tag }}" = "next" ]; then
nix develop -c bun scripts/apply_versions.ts --plan "$PLAN" --suffix "next.${{ github.run_number }}"
if [ "$DIST_TAG" = "next" ]; then
bun scripts/apply_versions.ts --plan "$PLAN" --suffix "next.$RUN_NUMBER"
else
nix develop -c bun scripts/apply_versions.ts --plan "$PLAN"
bun scripts/apply_versions.ts --plan "$PLAN"
fi
nix develop -c bun run build
nix develop -c bun run pack
nix develop -c bun run jsr:sync
bun run build
bun run pack
bun run jsr:sync

- uses: actions/setup-node@v5
- uses: actions/setup-node@v7
if: steps.mode.outputs.dry-run != 'true'
with:
node-version: 24
Expand All @@ -127,4 +135,6 @@ jobs:

- name: Publish
if: steps.mode.outputs.dry-run != 'true'
run: nix develop -c bun scripts/publish.ts --plan "$PLAN" --dist-tag "${{ steps.mode.outputs.dist-tag }}"
env:
DIST_TAG: ${{ steps.mode.outputs.dist-tag }}
run: bun scripts/publish.ts --plan "$PLAN" --dist-tag "$DIST_TAG"
42 changes: 28 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,28 @@ on:
pull_request:
workflow_dispatch:

# A pull request only needs its latest commit checked. A run on main waits
# for the one before it instead of cancelling it, so each one finishes.
concurrency:
group: test-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: nixbuild/nix-quick-install-action@v34
- run: nix develop -c bun install --frozen-lockfile
- run: nix develop -c bun run fmt:check
- run: nix develop -c bun run lint
- run: nix develop -c bun run check
- run: nix develop -c bun scripts/sync_jsr.ts --check
- run: nix develop -c bun run build
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: nixbuild/nix-quick-install-action@v35
# Load the development shell (flake.nix) into the job.
- uses: nicknovitski/nix-develop@v1
# The same gate as local development (justfile). Integration tests skip
# here; the test job runs them against the services.
- run: just ci

test:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -104,19 +114,23 @@ jobs:
# - GitHub Actions services don't support custom command options
# - Transactions require replica set mode (--replSet flag)
# - supercharge/mongodb-github-action handles replica set initialization
- uses: supercharge/mongodb-github-action@1.12.0
- uses: supercharge/mongodb-github-action@1.12.1
with:
mongodb-version: "7.0"
mongodb-replica-set: rs0
- uses: actions/checkout@v6
- uses: nixbuild/nix-quick-install-action@v34
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: nixbuild/nix-quick-install-action@v35
# Load the development shell (flake.nix) into the job.
- uses: nicknovitski/nix-develop@v1

- run: nix develop -c bun install --frozen-lockfile
- run: just install

- run: nix develop -c bun run test --coverage --coverage-reporter=lcov --coverage-dir=.coverage
- run: just coverage
timeout-minutes: 5

- uses: codecov/codecov-action@v5
- uses: codecov/codecov-action@v7
with:
files: ./.coverage/lcov.info
slug: probitas-test/probitas-packages
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ node_modules/
dist/
dist-pack/
packages/*/LICENSE
/.envrc
.direnv/
result
/.claude/worktrees/
81 changes: 81 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Probitas Packages

Monorepo containing core framework packages and client libraries for the
Probitas scenario-based testing framework.

- **Runtime**: Bun 1.4+ (pinned in `flake.nix`)
- **Registries**: npm (`@probitas-test/*`) and JSR (`@probitas/*`)
- **Framework packages**: builder, runner, reporter, core, discover, expect, and
the other non-client packages
- **Client packages**: `@probitas-test/client-*` (HTTP, gRPC, SQL, Redis,
MongoDB, and the other protocols)

`@probitas-test/probitas` (the user-facing entry point and CLI) is maintained
separately in [probitas](https://github.com/probitas-test/probitas).

## How it is built

- **Test first.** Red → green → refactor. Write the failing test before the code
that makes it pass.
- **Each layer holds one thing.** Put a fact in the one layer that owns it, and
nowhere else.

| Layer | Holds |
| ------------ | ------------------------------------------------------------------ |
| `docs/adr/` | one decision and why it was made |
| `docs/spec/` | the behaviour users and other components can rely on |
| Tests | the details that pin the behaviour down: rules, boundaries, tables |
| Code | how it is done |
| Commits | why a change was made |
| Comments | why it is not done another way |

Before writing, fixing or reviewing a record, read `docs/adr/README.md`;
before writing, fixing or reviewing a spec, read `docs/spec/README.md`. Follow
their writing order.
- **Dependencies are current.** Before adding or bumping one, look up its latest
release in the registry. Do not copy a version from memory or from another
repository. Client packages may depend only on what
[`.claude/rules/dependencies/client-packages.md`](.claude/rules/dependencies/client-packages.md)
allows.

The coding rules live in `.claude/rules/` (design, development, TypeScript,
logging, package structure); each applies to the paths named in its header.

## Quality gate

Run `just ci` before reporting a change as done. CI runs the same recipe.

Integration tests skip when their service is not reachable. Start the services
with `docker compose up -d` (`compose.yaml`) to run them locally; CI runs them
in the `test` job against service containers. When adding an integration test,
add its service to both `compose.yaml` and `.github/workflows/test.yml`.

When touching `package.json` exports or dependencies, run `just jsr-sync` so the
`deno.json` files stay in step (`just ci` checks them).

## Layout

| Path | What lives there |
| -------------------- | -------------------------------------------------------------- |
| `packages/` | the published packages, one directory per package |
| `internal/` | private workspace packages (the `bun:test` adapter) |
| `scripts/` | build, pack, JSR sync and release scripts |
| `docs/` | ADRs and specs |
| `.github/workflows/` | `test.yml` (quality gate and integration tests), `publish.yml` |

## Language

- README, docs and commit messages: English
- Code comments, log and error messages: English

## Commits

[Conventional Commits](https://www.conventionalcommits.org/) with a required
scope: the package name without its registry scope (`feat(runner): …`,
`fix(client-http): …`), several joined with `,` (`fix(runner,core): …`), and
`(*)` for repository-wide changes. Release versions are derived from the commit
types, so the type matters: `feat` is minor, `!` or `BREAKING CHANGE:` is major,
everything else is patch, and a `/unstable` scope is always patch.

[`.claude/rules/repository.md`](.claude/rules/repository.md) has the full
convention and how releases are made.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ framework package with unified API for writing scenarios.

### Prerequisites

- Bun 1.4+ (or use Nix: `nix develop`)
- Nix (`nix develop`, or copy `.envrc.sample` to `.envrc` for direnv), which
provides Bun 1.4+ and just
- Docker Compose (for integration testing services)

### Setup
Expand All @@ -76,11 +77,11 @@ framework package with unified API for writing scenarios.
git clone https://github.com/probitas-test/probitas-packages.git
cd probitas-packages

# Enter development environment (optional, using Nix)
# Enter the development environment
nix develop

# Install dependencies
bun install
just install

# Start integration test services
docker compose up -d
Expand All @@ -89,17 +90,17 @@ docker compose up -d
### Tasks

```bash
# Run all checks and tests (recommended before committing)
bun run verify
# Run everything CI checks (recommended before committing)
just ci

# Individual tasks
bun run fmt # Format code (dprint)
bun run lint # Lint code (Biome)
bun run check # Type check (tsc)
bun run test # Run tests
just fmt # Format code (dprint, nixfmt)
just lint # Lint code (Biome)
just typecheck # Type check (tsc)
just test # Run tests

# Coverage
bun run test --coverage
# Coverage (lcov report in .coverage/)
just coverage
```

### Integration Services
Expand Down Expand Up @@ -167,7 +168,7 @@ docs(*): update copyright headers
`client-http`)
- `feat:` → minor bump, `fix:`/`docs:`/`refactor:` → patch bump
- `BREAKING:` → major bump (except for `/unstable` scopes, always patch)
- Run `bun run verify` before committing
- Run `just ci` before committing

See [`.claude/rules/repository.md`](./.claude/rules/repository.md) for detailed
contribution guidelines.
Expand Down
Loading
Loading