Development
The authoritative contribution workflow is CONTRIBUTING.md in the repository; when the two disagree, CONTRIBUTING.md wins. Participation is governed by the code of conduct (Contributor Covenant 2.1).
Bug reports and feature requests go to GitHub issues. Security problems do not: see Security reporting.
Licence and sign-off
AutoAir is licensed under Apache-2.0, and contributions are accepted under the same licence (Apache-2.0 section 5 applies to anything you submit). There is no CLA and no DCO, so Signed-off-by lines are not needed. Only submit work you have the right to contribute.
Repository layout
| Path | Contents |
|---|---|
src/autoair/ | Python package: FastAPI app, Airflow plugin, CLI, spec, codegen, validation, storage, IAM, AI, MCP |
frontend/ | React 19 editor (Vite). npm run build writes both bundles into src/autoair/static/ |
tests/ | unit/, integration/ (real Airflow), golden/ (codegen snapshots), live/ (real services) |
docs/ | Reference documentation in Markdown |
website/ | This Docusaurus site, published to GitHub Pages |
deploy/ | Dockerfiles, the Compose demo, Helm values |
scripts/ | Dev servers, live-test bootstraps, doc generators, release checks |
The typed DAG specification is the interface between the UI, validation and code generation; tests mirror the backend domains.
Setup
You need uv, Node.js 22.18 or later, git and, for the end-to-end tests, Google Chrome.
git clone https://github.com/ctolon/autoair && cd autoair
uv sync # Python 3.12 venv with Airflow 3.3 and dev tools
(cd frontend && npm ci && npm run build) # editor bundles served by the plugin and `autoair serve`
(cd website && npm ci) # only when working on this site
uv run pre-commit install # checks on commit, mypy on push
The pre-commit hooks in .pre-commit-config.yaml run ruff (check and format), the configuration-reference, hard-coded-audit and version checks, prettier and eslint on changed frontend files, the MDX check on changed docs and actionlint on workflows; mypy runs before git push. Python tools come from uv.lock and the frontend tools from frontend/package-lock.json, so they match CI. Run everything with uv run pre-commit run --all-files; CI remains the gate.
Run it:
make dev-airflow # Airflow 3 standalone + plugin: http://localhost:8080 -> Browse -> DAG Builder
make serve # standalone AutoAir: http://127.0.0.1:8765/ui/
make ui-dev # Vite dev server with hot reload, proxying /api to `make serve`
uv run autoair local --open # no Airflow server needed
The whole stack (PostgreSQL, split Airflow, two AutoAir replicas, and optional Gitea, Redis, AI service, TLS and tracing) runs in Docker through make demo; see Docker Compose.
Checks and tests
make check # ruff, mypy --strict, hard-coded audit, config reference, tsc, eslint, prettier
make test # pytest (unit + integration against the installed Airflow) and vitest
make matrix # nox: every supported Airflow minor (3.0 to 3.3), the 3.4 pre-release, Python 3.10
make e2e # Playwright inside the Airflow UI; needs `make dev-airflow` running
make crawl # UI crawler: every menu, dialog, tab and inspector must render (about 25 minutes)
Focused runs:
uv run pytest tests/unit/test_codegen.py -q -k branch
uv run nox -s "tests(3.0)" # one Airflow minor (Airflow's core pins)
uv run nox -s "fresh(3.2)" # same, unpinned: newest upstream releases
uv run nox -s oldest # Python 3.10 + Airflow 3.0
cd frontend && npx vitest run src/lib # one vitest folder
cd frontend && npm run test:visual # visual regression (light and dark)
- Golden tests compare generated code with
tests/golden/expected/. When a change is intended, regenerate the snapshots and review the diff like code. - PostgreSQL tests (marker
postgres) needAUTOAIR_TEST_POSTGRES_URL, for example a throw-awaypostgres:17-alpine. - Live suites (
-m live) run against real FAB and Keycloak auth managers and GitLab; the bootstrap scripts are inscripts/and described indocs/deployment.md. Passing mock or contract tests is not proof that a live integration works. - UI changes need a look in light and dark mode, and in both the Airflow plugin and standalone mode. Invalid or partially entered input must never break a panel. Browser tests live in
frontend/e2e; the crawler exercises partially entered and invalid values. Verify with the crawler and end-to-end tests rather than fuzzing.
Code style
-
Python:
ruff(lint and format, line length 100) andmypy --strictforsrc/. Public functions are typed. -
No hard-coded operator values. Values that operators may need to change become settings with a description (
src/autoair/settings.py,sections.py). Every literal timeout, size or URL is triaged inscripts/hardcoded_decisions.json:uv run python scripts/scan_hardcoded.py # untriaged findingsuv run python scripts/scan_hardcoded.py --write # full report in .artifacts/hardcoded-audit.mduv run python scripts/scan_hardcoded.py --check # what CI runs: all triaged, none stalescripts/hardcoded_decisions.jsonis the committed source of truth; the markdown report is a local, gitignored file (CI uploads it as thehardcoded-auditartifact). -
Settings reference: after adding or changing a setting, run
uv run python scripts/gen_config_docs.pyto regeneratedocs/configuration-reference.md(this site's configuration reference is generated from it). CI fails when it is stale. -
TypeScript: eslint, prettier (
npm run format) andtsc --noEmit. Never editfrontend/src/api/gen/by hand: after backend API changes runmake codegenand commitfrontend/openapi.jsontogether with the regenerated client. -
Keep commits focused, with messages in the imperative mood ("Add GitLab draft MRs").
Documentation and changelog
- User documentation lives on this site (
website/docs/); the in-repository reference for contributors lives indocs/. Each topic is written in one place; see Where documentation lives and, for how pages are written, Documentation. make docsbuilds the site andmake docs-servestarts it with live reload athttp://localhost:3000/autoair/. The build fails on broken links.- User-visible changes get an entry under
## [Unreleased]in CHANGELOG.md, in the Added, Changed, Deprecated, Removed, Fixed or Security section.
Pull requests
- Fork the repository, or create a branch if you have access. Never push to
main. - Make the change with tests.
make check testmust pass locally. - Open the pull request using the template. Link the issue, describe user-visible effects, and attach light and dark screenshots for UI changes.
- CI must be green. The CI OK check summarises lint, the Python by Airflow matrix, PostgreSQL, the frontend, end-to-end tests, the website, packaging and the Docker smoke test.
- A review by a code owner (
.github/CODEOWNERS) is required. Pull requests are squash-merged.
Releases (maintainers)
-
Bump the version in
pyproject.toml,src/autoair/__init__.py,frontend/package.jsonandwebsite/package.json.uv run python scripts/check_release.pychecks that they agree. -
Move the
[Unreleased]entries inCHANGELOG.mdunder## [X.Y.Z] - YYYY-MM-DDand update the comparison links. -
Merge to
main, then push a signed tag:git tag -s vX.Y.Z -m "AutoAir X.Y.Z" && git push origin vX.Y.Z. -
.github/workflows/release.ymlchecks that the tag matches the package version and thatCHANGELOG.mdhas a section for it, re-runs CI, builds the sdist and wheel (with the editor bundles), publishes to PyPI through trusted publishing, pushes the multi-arch imageghcr.io/ctolon/autoairwith SBOM and build provenance, and creates the GitHub Release from the changelog section. Running the workflow manually (workflow_dispatch) builds and checks everything without publishing.For an urgent fix, a tag message containing
[fast-release](git tag -a vX.Y.Z -m "AutoAir X.Y.Z [fast-release]") skips the CI test matrix inside the release workflow. The tag and version checks, the build,twine check, the packaged-artifact checks and thepypi/releaseenvironment approvals still run. Run the tests that cover the change locally first; a manual dry run can skip the matrix the same way withgh workflow run release.yml --ref main -f fast=true. The documentation site redeploys when the release is published.
Publishing credentials belong in GitHub environments or trusted publishing, never in the repository.