{ lib, pkgs, ... }: let cilib = import ./. {inherit lib pkgs;}; inherit (cilib.helpers) filterAttrsRec customMapAttrs toYaml; inherit (cilib.jobDeps) mkJobDeps; inherit (cilib.jobRun) mkJobRun; inherit (cilib.jobPatch) mkJobPatched; in { mkPipeline = { name, pipeline, }: let jobs = filterAttrsRec (n: v: v != null) pipeline.jobs; rest = filterAttrsRec (n: v: v != null) (builtins.removeAttrs pipeline ["jobs" "config"]); # this allows us to nix build this to get all the mentioned dependencies from the binary cache # pro: we don't have to download everything, just the deps for the current job # before, we just allowed pkgs inside the script string directly, but now with the ability to source this file # we can support different architectures between runners (eg. the arch of the initial runner does not matter) jobsMappedForDeps = customMapAttrs (key: job: { name = "gitlab-ci:pipeline:${name}:job-deps:${key}"; value = mkJobDeps {inherit key job;}; }) jobs; # allows the user to directly run the script jobsMappedForScript = customMapAttrs (key: job: { name = "gitlab-ci:pipeline:${name}:job:${key}"; value = mkJobRun { inherit key job; jobDeps = jobsMappedForDeps."gitlab-ci:pipeline:${name}:job-deps:${key}"; }; }) jobs; # build the deps specific for this job before anything, this way the deps should be fetched from the cache jobsPatched = customMapAttrs (key: job: { name = key; value = assert lib.assertMsg (builtins.elem job.stage (rest.stages or [])) "stage '${job.stage}' of job '${key}' does not exist"; mkJobPatched { inherit key job; pipeline_name = name; }; }) jobs; in { packages = # gitlab-ci:pipeline: # gitlab-ci:pipeline::job: # gitlab-ci:pipeline::job-deps: { "gitlab-ci:pipeline:${name}" = toYaml "gitlab-ci-${name}.yml" (rest // jobsPatched); } // jobsMappedForDeps // jobsMappedForScript; finalConfig = rest // jobsPatched; }; }