git clone git@github.com:dualentry/dualentry-cli.git
cd dualentry-cli
uv sync --dev
uv run pre-commit installuv.lock is committed, and CI runs uv sync --dev --locked, which fails if the lockfile
is out of date with pyproject.toml. So whenever you add, remove, or change a dependency:
uv lock # regenerate uv.lockCommit the updated uv.lock alongside your pyproject.toml change, or CI will fail with
The lockfile at uv.lock needs to be updated, but --locked was provided.
To pick up newer versions of existing dependencies, run uv lock --upgrade deliberately —
it is not something that happens on its own. Expect to fix new ruff findings when you do,
since the lint config selects ALL rules and each ruff release can add more.
uv run dualentry --help
uv run dualentry invoices listuv run ruff check .
uv run ruff format --check .uv run pytest
uv run pytest --cov=dualentry_cli --cov-report=term-missing- Create a branch from
main - Make your changes
- Ensure linting and tests pass
- If you touched dependencies, run
uv lockand commituv.lock - Open a PR against
main
Releases are triggered by publishing a GitHub Release. CI builds binaries and updates the Homebrew tap automatically.
- Update
CHANGELOG.mdwith the new version and changes - Commit and push to
main - Go to GitHub → Releases → Draft a new release
- Click Choose a tag → type the new version (e.g.,
v0.2.0) → Create new tag - Set the title:
DualEntry CLI v0.2.0 — <summary> - Paste the changelog entry as the release body
- Click Publish release
CI will:
- Build binaries for macOS (arm64, x86_64) and Linux (x86_64)
- Stamp the version from the tag into the binary
- Upload binaries to the GitHub Release
- Update the Homebrew tap formula with new SHA256 hashes
Users upgrade via brew upgrade dualentry or re-running the install script.
We use Semantic Versioning:
- Patch (
0.1.1) — bug fixes - Minor (
0.2.0) — new features, backward compatible - Major (
1.0.0) — breaking changes