Using CI/CD and GitHub workflows¶
This guide explains the continuous integration and continuous deployment (CI/CD) pipelines used in disdantic. It outlines the standard pathways, development cycles, and what standards must be met to contribute to the repository.
Understand the architecture¶
The repository utilizes a modular, standardized GitHub Actions architecture. Workflows are categorized into core lifecycle events (prefixed with pipeline-) and utility triggers (prefixed with util-).
Our CI/CD pipelines ensure that all code merged into the main branch meets strict code quality, type-safety, testing, and security standards.
Navigate standard development pathways¶
When contributing to this repository, your code will travel through the following pipeline stages.
1. The pull request cycle (pipeline-development.yml)¶
When you open a Pull Request against main, the pipeline-development.yml workflow is triggered. This is the primary gateway for all code changes.
What it enables:
- Quality Gates: Runs code quality and formatting checks (
hatch run python:lint,hatch run project:lint,hatch run oci:lint) and static type verification (hatch run python:types) to enforce consistent standards. - Security Audits: Scans for vulnerabilities in dependencies and code patterns using
detect-secrets,pip-audit(via Python security checks), andtrivy/dockle(via OCI security checks). - Testing: Runs the Python unit, integration, and OCI structure tests. The PR will be blocked from merging if any tests fail.
- Documentation Previews: Verifies that the Zensical documentation can be built cleanly.
Validation Standards: Your PR must pass all checks before it can be merged. We require strict adherence to PEP 8/Ruff, Python type annotations, and all tests must pass with adequate coverage.
2. Main branch validation (pipeline-main.yml)¶
Once your PR is reviewed and merged into main, the pipeline-main.yml workflow acts as a secondary validation layer.
What it enables:
- Full Test Suite: Runs unit, integration, and full end-to-end (e2e) tests to ensure the merged changes didn't introduce regressions.
- Documentation Deployment: Builds and deploys the
latestversion of the documentation site to thegh-pagesbranch. - Sanity Checks: Re-runs quality and security checks on the finalized codebase.
3. Nightly and weekly pipelines¶
To catch configuration drift and conduct deeper analysis, we run scheduled workflows:
- Nightly (
pipeline-nightly.yml): Runs daily at 00:00 UTC. It performs extended regression testing, builds alpha container images, and does deep security analysis. - Weekly (
pipeline-weekly.yml): Runs every Sunday at 00:00 UTC. Focused on dependency hygiene, checking for outdated constraints and ensuring the test suite is robust against external changes.
Manage releases (pipeline-release.yml)¶
Releasing a new version can be done in two ways:
-
Manual UI Trigger (Recommended): A maintainer triggers the
CI — Releaseworkflow manually via the GitHub Actions UI. -
Inputs: Requires entering a version tag matching strict semver (e.g.,
v1.2.0). - Branch Constraints: Can only be started on the
mainbranch or areleases/*branch. If triggered on any other branch or tag ref viaworkflow_dispatch, the workflow fails theinit-gatejob and exits. - Process: The workflow runs all quality, testing, and integrity checks. If they pass, it automatically tags the current commit with the entered version and pushes it to origin.
-
Unified Release Publishing: Pushing the tag using the job's
GITHUB_TOKENsuccessfully creates the remote tag without triggering recursive pipeline runs. The publishing jobs (publish-pythonandpublish-oci) then execute immediately within the same manual run as soon as the tagging step succeeds. No Personal Access Tokens (PATs) or manual trigger restarts are required. -
Direct Tag Push: When a maintainer pushes a
v*.*.*tag (e.g.,v1.2.0) directly to origin, the workflow is triggered on the tag ref. -
It performs a final, full verification of the entire test suite on the tag.
- It builds immutable Python packages (sdist and wheel).
- It attests the build provenance using OIDC.
- It publishes the artifacts to PyPI and the container image to the GitHub Container Registry (GHCR).
Release Security & Environments¶
To prevent unauthorized releases, we implement a Gate Job pattern using two-stage approvals bound to the release GitHub Environment:
- Required Reviewers & Dual Approval: Repository Administrators should configure the
releaseenvironment under Settings -> Environments -> release to require approvals from designated release managers. The workflow requires two approvals: one atinit-gate(to authorize starting the verification checks) and a second atrelease-gate(to authorize tagging and publishing after all verification gates have succeeded). - Deployment Branches & Early Fail: Set the deployment branch policy to Selected branches allowing only
main,releases/*, and tag patterns (such asv*orrefs/tags/v*) to run jobs under this environment. Additionally,init-gateperforms shell validation checking that the ref is a valid version tag (e.g.v1.2.3) or that branch execution (mainorreleases/*) was explicitly triggered byworkflow_dispatch. If these conditions are not met,init-gatefails immediately. - Unified Publishing Gate & Gate Job Pattern: The
release-gatejob validates all previous gates (quality-gate,functional-gate,integrity-gate, ande2e-gate) and propagates thedefault_pythonconfiguration output down a linear dependency chain:release-gate->tag-release->publish-python->docs/publish-oci. This prevents GHA from requesting unnecessary additional approvals and simplifies job conditionals. - Publish Input Overrides: Configured
publish-python(GitHub Release tag name),publish-oci(OCI image tag name), anddocs(docs version folder name) to use${{ github.event.inputs.version_tag || github.ref_name }}. Decoupleddocsentirely frominit-gateso thatdocsandpublish-ocionly depend onpublish-python.
Utilize custom actions¶
To maintain consistency and reduce duplication, our lifecycle pipelines rely on composite actions located in the .github/actions/ directory:
- Python Environment:
python/tests: Orchestrates Python test suite execution (unit, integration, e2e).python/quality: Defines the exact linting (Ruff) and type-checking (Mypy/Ty) commands.python/buildandpython/publish: Standardizes Python package generation and PyPI distribution.- OCI Containers:
oci/tests: Runs OCI Container Structure Tests (CST).oci/quality: Lint Dockerfiles with Hadolint and Docker Compose configurations.oci/buildandoci/publish: Builds and registers production-ready container images.- Project-wide Utilities:
project/quality: Enforces repository-wide guidelines (mdformat, yamlfix, taplo).project/docs: Handles building MkDocs/Zensical sites.
By relying on these shared actions, we ensure that the exact same linting and test rules are applied whether you are testing a PR, running a nightly build, or deploying a release.
Next Steps:
- See the Contributing Guide for details on how to set up your local environment.