Contributing¶
Thanks for considering contributing to Modern Django Starter! This page covers setting up a development environment, running the checks, and maintaining the docs.
Prerequisites¶
- Python 3.12+
- uv
- Node.js and npm — only needed if you test frontend pipeline generation
Setup¶
git clone https://github.com/CasualEngineerZombie/modern-django-starter.git
cd modern-django-starter
uv sync
Run the CLI in development mode:
or invoke the tests:
Running the checks¶
CI runs linting, formatting, type checking, and tests on Python 3.12, 3.13, and 3.14. Run the same checks locally:
Integration tests¶
tests/test_generated_projects_e2e.py contains an end-to-end matrix that generates a
representative project for each major configuration combination, installs its
dependencies into a temporary virtual environment, runs manage.py check,
runs migrations, and executes the generated project's own test suite.
Docker-enabled configurations are also validated with docker compose config
(when Docker is available).
These tests download and install packages, so they are skipped unless you opt in:
RUN_DJANGO_INTEGRATION_TESTS=1 uv run pytest -q \
tests/test_api_only_integration.py \
tests/test_storage_dependencies.py \
tests/test_stripe_webhook_secret.py \
tests/test_generated_projects_e2e.py \
tests/test_aws_s3_integration.py
The matrix lives at the top of test_generated_projects_e2e.py:
MATRIX— runnable configurations (SQLite) that must pass check, migrate, and the generated test suite.CHECK_ONLY_MATRIX— feature-maximal PostgreSQL configurations that must install and passmanage.py check, but cannot migrate without a live database; their Docker setups are covered by the Compose validation.POSTGRES_ENTRY— a PostgreSQL configuration thatPostgresProjectIntegrationTestsboots against a real database: it starts the generated project's owndbservice withdocker compose up -d db, then runs migrate and the generated test suite against it (requires Docker).DockerComposeStackIntegrationTests— a full-stack boot (issue #16): it runsdocker compose up -d --build webon a docker+PostgreSQL configuration, waits for thewebhealthcheck to reporthealthy, and asserts the entrypoint applied migrations and static files. This proves a freshdocker compose upproduces a bootable, initialized project.
When you add a configuration option to the generator, add (or extend) a matrix entry here so the new combination is proven to boot, not just render.
AWS S3 round trip (kumo emulator)¶
tests/test_aws_s3_integration.py generates an AWS-storage project and runs a
real django-storages round trip (save → open → delete) against
kumo, an AWS emulator with an S3-compatible
API. The generated project is pointed at the emulator via its
AWS_S3_ENDPOINT_URL setting, so the exact storage code path production uses
is exercised. To run it against the compose kumo:
docker compose -f docker-compose.act.yml up -d kumo
RUN_DJANGO_INTEGRATION_TESTS=1 AWS_S3_ENDPOINT_URL=http://localhost:4566 \
AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test \
uv run pytest -q tests/test_aws_s3_integration.py
Without AWS_S3_ENDPOINT_URL the test skips, so unit runs stay hermetic.
Run CI locally with act¶
ci-local.sh runs the CI workflow locally with
act (install: winget install nektos.act), so there
is no wait for GitHub Actions results on every push:
./ci-local.sh # every ci.yml job
./ci-local.sh -j integration # just the kumo-backed integration job
The integration tests reach the compose kumo on localhost:4566 (act runs job
containers on the host network, and ci-local.sh starts the emulator first);
GitHub-hosted runners use the workflow's own kumo service container instead.
.act.env is machine-local (gitignored) — tracked defaults live in
.act.env.example. One caveat: DockerComposeStackIntegrationTests is
skipped under act (ACT=true), because its ./staticfiles bind mount points
at a path inside the job container that the outer Docker daemon cannot see.
Project layout¶
modern_django_starter/
├── cli.py # Click CLI + interactive prompts
├── generator.py # ProjectGenerator — writes all project files
└── templates/ # Jinja2 templates used to render generated files
├── settings/
├── templates/
├── static/
├── requirements/
├── .github/workflows/
└── *.j2
cli.pycollects choices and prints the summary table.generator.pyrenders templates and writes the project tree.- The
templates/directory mirrors the layout of a generated project. Each.j2file is a Jinja2 template rendered withproject_nameandconfig.
When you change generated output, make sure the existing tests still pass and add a
test for new behavior. The existing suite lives in tests/.
Keeping the docs in sync¶
The documentation site sources live in docs/. When you change generated output or
the CLI, update the relevant page:
- New/renamed options →
configuration.mdandcli-reference.md - New generated files →
generated-project.md - New integrations →
integrations.md
Preview docs locally¶
The build must pass in strict mode, since CI deploys with --strict.
Docs deployment
Pushing to main automatically rebuilds and deploys the site to
https://mds.rianbarriga.com via .github/workflows/docs.yml.
Submitting changes¶
- Fork the repository and create a feature branch
(
git checkout -b feature/your-feature). - Make your changes.
- Run all checks above.
- Update or add tests and docs as needed.
- Push and open a pull request against
main.
Releases¶
Versioning policy (SemVer)¶
This project follows Semantic Versioning:
- Patch (
0.3.x,1.0.x) — bug fixes and backward-compatible corrections only. Bug fixes ship in patches; features never ship in patches. - Minor (
0.x.0,1.x.0) — new features, new configuration options, or new integrations that stay backward compatible. - Major (
1.0.0,2.0.0) — breaking API changes. 1.0.0 freezes and stabilizes the public API (CLI flags, generated project layout, template names); nothing that consumers rely on changes without a major bump.
The roadmap milestones (currently v0.3.x patches through 1.0.0) are tracked in
Linear; each patch milestone maps to one bug-fix+regression-test GitHub issue and
one single-commit PR.
Cutting a patch release¶
Before you start, the Integration gate must pass: run the full E2E matrix
(integration tests) with RUN_DJANGO_INTEGRATION_TESTS=1
and confirm it is green, since that is the only suite that proves a generated
project boots, not just renders.
- Merge the patch PRs to
mainand confirm CI is green (Lint, Type check, Test × 3, Integration, Package). - Bump the version in two places —
__version__inmodern_django_starter/__init__.pyandversioninpyproject.toml— and lettests/test_metadata.pyprove they match. - Update
CHANGELOG.md— move the patch entry out of its "Unreleased" section into a dated## [0.3.x] - YYYY-MM-DDsection, and update the version links at the bottom. - Tag and push:
Pushing the tag triggers publish.yml (PyPI release); pushing main already
redeployed the docs via docs.yml.
5. Update the roadmap in Linear — flip the milestone's issues to Done.
License¶
MIT — see the LICENSE file.