ci/praktika/native_jobs.md
This file defines special "native" jobs that are built into the Praktika CI framework. These jobs handle critical workflow operations like configuration, Docker image building, and finalization.
Native jobs are Praktika's system-level jobs that run at key points in the CI workflow lifecycle:
_config_workflow) - Runs at workflow start to configure the entire CI run_build_dockers) - Build Docker images for AMD, ARM, and multi-platform manifests_finish_workflow) - Runs at workflow end to collect results and set final statusThese jobs are distinguished from user-defined jobs and are automatically included in every workflow when enabled via workflow settings.
The file defines several job configurations:
_workflow_config_job - Configuration job that runs on CI_CONFIG_RUNS_ON runners_docker_build_manifest_job - Merges AMD/ARM manifests into multi-platform images_docker_build_amd_linux_job - Builds AMD64 Docker images_docker_build_arm_linux_job - Builds ARM64 Docker images_final_job - Finalization job that runs even if workflow is cancelled_config_workflow)The configuration job performs critical setup at the start of each workflow run:
Repository Setup
GitHub Integration
Pre-flight Checks
Docker Digest Calculation
RunConfig for cache and build decisionsJob Filtering
check_affected_jobs below)Cache Configuration
RunConfigReport Initialization
check_affected_jobsThis function implements intelligent job skipping based on file changes, significantly reducing CI runtime for PRs that only touch specific parts of the codebase.
┌─────────────────────────────────────┐
│ Get changed files from PR/commit │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Find affected Docker images │
│ (Docker images that need rebuilding)│
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ For each job (excluding native Praktika jobs): │
│ │
│ Check if job is affected by: │
│ 1. Requires artifacts from affected jobs? │
│ 2. Runs in an affected Docker image? │
│ 3. Directly affected by changed files? │
│ (via job.is_affected_by(changed_files)) │
└──────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ If AFFECTED: │
│ - Track job's artifacts as affected │
│ - Track job's required artifacts │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ If NOT AFFECTED: │
│ - Jobs with no artifacts → SKIP │
│ - Jobs with artifacts → DEFER │
│ (may still be needed) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Second pass: Unaffected jobs with artifacts │
│ │
│ For each deferred job: │
│ - If artifacts are in all_required_artifacts │
│ → CANNOT SKIP (other jobs need these artifacts) │
│ - If artifacts not required anywhere │
│ → SKIP (not affected and not needed) │
└─────────────────────────────────────────────────────┘
Affected Jobs: A job is considered affected if:
Job.is_affected_by)Artifact Dependency Chain: The algorithm tracks artifact dependencies to ensure that if Job B requires artifacts from Job A, and Job A is affected, then Job B must also run (even if Job B's code wasn't changed).
Ordering-Only Dependencies: When a job requirement matches a job name (rather than an artifact name), it's treated as an ordering-only dependency. Job names in requirements are excluded from all_required_artifacts to prevent keeping alive unnecessary jobs. If you need artifacts from a job, reference the artifact name directly, not the job name.
Deferred Decision: Jobs that produce artifacts but aren't directly affected cannot be immediately skipped - they're only skipped if no other affected job requires their artifacts.
Changed files: src/database/query_parser.cpp
Jobs:
- build_parser (provides: parser_binary, runs in: builder_image)
- build_server (requires: parser_binary, provides: server_binary)
- test_ui (requires: server_binary)
- build_docs (provides: documentation)
Result:
1. builder_image is affected (contains src/database/)
2. build_parser is AFFECTED (runs in affected Docker image)
- Adds "parser_binary" to affected_artifacts
3. build_server is AFFECTED (requires affected artifact "parser_binary")
- Adds "server_binary" to affected_artifacts
4. test_ui is AFFECTED (requires affected artifact "server_binary")
5. build_docs is SKIPPED (not affected, no one needs "documentation")
Example: Ordering-Only Dependencies
Changed files: tests/integration/test_new_feature.py
Jobs:
- Job D (test_new_feature, directly affected)
- requires: ["Job C"] (job name → ordering dependency)
- Job C (setup_test_env, provides: nothing)
- requires: ["artifact_b"] (artifact name → data dependency)
- Job B (build_artifact, provides: ["artifact_b"])
Result:
1. Job D is AFFECTED (directly by changed files)
- Job D requires "Job C" (matches a job name)
- Job names indicate ordering-only dependencies
- "Job C" is NOT added to all_required_artifacts
2. Job C is SKIPPED (not affected, provides nothing)
3. Job B is SKIPPED (not affected, "artifact_b" not in all_required_artifacts)
- Only artifact names (not job names) are tracked in all_required_artifacts
- Job C's requirement "artifact_b" was never added because Job C is not affected
_is_praktika_job are always runaffected_artifacts for cases where artifact reports reference job names instead of artifact namesall_required_artifacts from affected jobs, the algorithm checks if each requirement matches a job name. If it does, the requirement is excluded from all_required_artifacts as job names indicate ordering-only dependencies. Only artifact names are added to track actual data dependenciesworkflow_config.filtered_jobs with the reason for skippingThe function returns a Result object containing:
The workflow configuration is persisted to filesystem via RunConfig.dump() and used by all subsequent jobs in the workflow.
_finish_workflow)[Placeholder: This job runs at the end of the workflow to collect all job results, check for failures, post final status to GitHub, run post-hooks, and set the "Ready for Merge" status if enabled.]