Development¶
Setup¶
The complete development workflow requires Bash and Unix command-line utilities. On Windows, use WSL for the following just recipes, changelog preparation, and releases. Install all development tools inside WSL and use a separate checkout in its Linux filesystem. Keep native Windows and WSL virtual environments separate.
Install Git, Python 3.12, uv, just, git-cliff, and ripgrep. Then run:
Use just reset followed by just setup to recreate the local runtime
environment. just clean removes generated caches and build artifacts
while keeping the environment.
Native Windows focused checks¶
Native Windows runtime development and testing can use PowerShell without just or Bash. Install Git and uv, then run:
uv sync --locked --all-groups
uv run ruff check .
uv run ruff format --check .
uv run pyrefly check
uv run pytest --tb=short
These commands do not run the complete quality suite. Run just check
in the separate WSL checkout before submitting a change. Git Bash may
provide the shell and utilities used by just, but the complete native
just workflow is not a supported development path. Keep tracked shell
scripts in LF format so their shebangs work in WSL.
Native Windows stores banip data under the Windows user profile; WSL uses its own Linux home directory. Do not assume they share local data. Use UTF-8 text files and quote paths containing spaces. Windows file permissions differ from Unix permissions, and open files can prevent replacement: close editors or other programs holding data files open before retrying a failed configuration or database update.
Quality checks¶
Run the complete local quality suite with:
This runs formatting and lint checks, static type checks, tests, the strict documentation build, and the direct-dependency license policy. The individual recipes remain available when a focused check is more appropriate:
CI keeps the complete Quality suite on Ubuntu. The Windows runtime
job runs the full pytest suite, builds distributions, tests installed
wheels and source distributions with local fixtures, and checks a
PowerShell virtual-environment installation. Windows coverage uses
Python 3.12 on windows-latest; it does not certify every Windows
version or architecture. Runtime fixture tests require no MaxMind
credentials or live feed downloads.
Run just docs-serve to preview documentation locally. The generated
site/ directory is not tracked. GitHub Pages builds the same strict
site after documentation changes reach main.
Country-code maintenance¶
Compare the supported country codes with the current GeoNames
countryInfo.txt dataset:
This network-dependent maintenance check is intentionally separate from
just check. It ignores the obsolete AN and CS rows retained by
GeoNames and verifies every other upstream code against runtime
validation. The offline test suite keeps the country-code reference
synchronized with the runtime set.
Changelog and releases¶
Pull-request titles use Conventional Commits because squash merges make
the title the commit subject on main. CI validates the title. The
supported user-facing types are:
| Type | Changelog section |
|---|---|
feat |
Added |
change |
Changed |
deprecate |
Deprecated |
remove |
Removed |
fix |
Fixed |
security or fix(security) |
Security |
perf |
Performance |
deploy |
Deployment & Operations |
docs |
Documentation |
build(deps) or build(deps-dev) |
Dependencies |
revert |
Reverted |
Use an optional scope when it adds useful context, for example
fix(config): reject an invalid country or
deploy(release): validate package artifacts. Mark a breaking change
with !, as in change!: rename a configuration key, and explain the
migration in the commit body's BREAKING CHANGE: footer. Routine
build, chore, ci, refactor, style, and test commits do not
appear in the changelog unless they are breaking.
Preview changelog-visible commits since the latest release without changing files:
Prepare a release from a clean release-preparation branch with an explicit canonical PEP 440 version:
just bump X.Y.Z
just check
git add CHANGELOG.md changelogs pyproject.toml uv.lock
git commit -m "chore(release): prepare for X.Y.Z"
The bump command updates synchronized project versions and the lockfile,
generates the release section, and restores the original files if any
step fails. It is safe to rerun the same untagged version after adding
release changes. Patch and prerelease entries remain in the active
X.Y line; starting a new minor or major line moves older entries to
the changelog archive.
After the release-preparation change is merged, update local main and
create the release tag:
Tagging requires a clean main that exactly matches origin/main,
synchronized metadata, committed release notes, and a tag that does not
already exist. It creates and pushes one annotated vX.Y.Z tag. The tag
workflow validates the release candidate, builds and smoke-tests the
wheel and source distribution, publishes the distributions to a package
index, and then publishes the GitHub Release.
Prerelease tags such as vX.Y.Zrc1 publish to TestPyPI and create a
GitHub prerelease. Stable tags such as vX.Y.Z publish automatically to
PyPI and create a stable GitHub Release. The GitHub release is not
created if the corresponding package-index publication fails.
Stable releases move the mutable latest Git tag only after PyPI and
GitHub publication succeed. The workflow never moves latest for a
failed release or a prerelease.
Do not attach a GitHub Release to latest or configure it as an
immutable or protected tag. The release workflow requires permission to
force-update this one mutable installation ref.
Promote a prerelease by preparing and tagging the matching stable
version, such as X.Y.Z. If the promotion has no additional
changelog-visible commits, the release notes record the promotion from
the prerelease.
Trusted publishing setup¶
The release workflow uses PyPI Trusted Publishing and does not use long-lived API tokens. It requires the following repository and package index configuration:
- Create GitHub environments named
testpypiandpypi. Do not add a deployment approval rule when releases should remain fully automatic. - Configure a trusted publisher for the
banipproject on TestPyPI and PyPI. Use ownergeozeke, repositorybanip, workflowrelease.yml, and the matching GitHub environment name. - Allow GitHub Actions read and write workflow permissions so the
stable release job can update the
latesttag.
Dependency updates and security¶
Dependabot checks direct uv and GitHub Actions dependencies weekly. Minor and patch uv updates are grouped into one pull request, while major uv updates and GitHub Actions updates remain individual. Dependabot automatically rebases open pull requests when its scheduled check runs or the target branch changes.
Eligible minor and patch updates receive squash auto-merge only after
the required Quality and Dependabot security gate checks succeed.
Major updates, updates without recognized semantic-version metadata,
and pull requests with maintainer changes require manual review and
merging.
The security workflow runs independent repository scanning, Python
dependency auditing, direct-dependency license validation, and CodeQL
analysis for Dependabot pull requests, relevant pushes to main, its
weekly schedule, and manual runs. Each job writes a summary table while
the corresponding step log contains full details. The workflow creates
no issue, dependency commit, or remediation pull request.
Repository administrators should enable the dependency graph and Dependabot Alerts in the repository's security settings. Leave automatic Dependabot security updates disabled when remediation pull requests should remain maintainer-controlled. For scheduled workflow failure email, enable Actions email notifications and select the option to notify only for failed workflows.
When an audit finds a vulnerable transitive dependency, prepare one
fix(security): pull request for compatible findings from that audit
cycle. Use the resolver rather than editing uv.lock by hand:
If the parent dependency excludes every fixed version, update or replace the parent instead of forcing an incompatible transitive version. Document any temporary risk acceptance or mitigation in the security pull request.
GitHub branch protection for main must require branches to be up to
date and require the Quality, Windows runtime, and
Dependabot security gate checks.
Repository administrators must also enable squash merging and
auto-merge and allow GitHub Actions read and write workflow permissions.