feat: initial v3 rewrite

This commit is contained in:
technofab 2025-09-01 15:04:20 +02:00
commit 0952ab4145
No known key found for this signature in database
32 changed files with 1457 additions and 0 deletions

View file

@ -0,0 +1,32 @@
{
lib,
cilib,
}: rec {
inherit
(import ./root.nix {
inherit lib pipelineSubmodule soonixSubmodule;
})
configSubmodule
nixCiSubmodule
;
inherit
(import ./pipeline.nix {
inherit lib cilib jobSubmodule;
})
pipelineConfigSubmodule
pipelineSubmodule
;
inherit
(import ./job.nix {
inherit lib cilib;
})
jobConfigSubmodule
jobSubmodule
;
inherit
(import ./soonix.nix {
inherit lib cilib;
})
soonixSubmodule
;
}

131
lib/impl/modules/job.nix Normal file
View file

@ -0,0 +1,131 @@
{
lib,
cilib,
...
}: let
inherit (lib) mkOption types filterAttrs;
inherit (cilib.helpers) filterUnset mkUnsetOption;
in rec {
jobConfigSubmodule = {pipelineConfig, ...}: {
options = {
enable = mkOption {
description = "Transform this job to a nix-configured one";
type = types.bool;
default = pipelineConfig.nixJobsByDefault;
};
deps = mkOption {
description = "Dependencies to inject into the job before running it";
type = types.listOf types.package;
default = [];
};
enableRunnerCache = mkOption {
type = types.bool;
default = false;
description = ''
Cache this job using the GitLab Runner cache.
Warning: useful for tiny jobs, but most of the time it just takes an eternity.
'';
};
runnerCacheKey = mkOption {
type = types.str;
default = "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG";
description = "Cache key to use for the runner nix cache. Requires enableRunnerCache = true";
};
};
};
jobSubmodule = {
name,
config,
pipelineName,
pipelineConfig,
...
}: let
#
# GITLAB OPTIONS
#
gitlabOptions = {
stage = mkOption {
type = types.str;
};
image = mkUnsetOption {
type = types.str;
};
variables = mkUnsetOption {
type = types.attrsOf types.str;
};
before_script = mkUnsetOption {
type = types.listOf types.str;
};
script = mkOption {
type = types.listOf types.str;
};
after_script = mkUnsetOption {
type = types.listOf types.str;
};
artifacts = mkUnsetOption {
type = types.attrs; # TODO: more granular
description = '''';
};
rules = mkUnsetOption {
type = types.listOf types.attrs;
};
allow_failure = mkUnsetOption {
type = types.bool;
};
};
in {
options =
{
nix = mkOption {
description = "Nix-GitLab-CI config options for this job";
type = types.submoduleWith {
modules = [jobConfigSubmodule];
specialArgs.pipelineConfig = pipelineConfig;
};
default = {};
};
finalConfig = mkOption {
internal = true;
type = types.attrs;
};
depsDrv = mkOption {
internal = true;
type = types.package;
};
runnerDrv = mkOption {
internal = true;
type = types.package;
};
packages = mkOption {
internal = true;
type = types.attrsOf types.package;
};
}
// gitlabOptions;
config = let
attrsToKeep = builtins.attrNames gitlabOptions;
in {
finalConfig = cilib.mkJobPatched {
key = name;
job = filterUnset (filterAttrs (n: _v: builtins.elem n attrsToKeep) config);
nixConfig = config.nix;
inherit pipelineName;
};
depsDrv = cilib.mkJobDeps {
key = name;
job = config.finalConfig;
nixConfig = config.nix;
};
runnerDrv = cilib.mkJobRun {
key = name;
job = config.finalConfig;
jobDeps = config.depsDrv;
};
packages = {
"gitlab-ci:pipeline:${pipelineName}:job-deps:${name}" = config.depsDrv;
"gitlab-ci:pipeline:${pipelineName}:job:${name}" = config.runnerDrv;
};
};
};
}

View file

@ -0,0 +1,101 @@
{
lib,
cilib,
jobSubmodule,
...
}: let
inherit (lib) mkOption types filterAttrs mergeAttrsList pipe mapAttrs;
inherit (cilib.helpers) filterUnset mkUnsetOption toYaml toYamlPretty;
pipelineConfigSubmodule = {rootConfig, ...}: {
options = {
nixJobsByDefault = mkOption {
description = ''
Whether to transform all jobs to nix-configured jobs by default.
If false, you need to set `nix.enable` for each job you want to be transformed.
'';
type = types.bool;
default = rootConfig.nixJobsByDefault;
};
};
};
pipelineSubmodule = {
name,
config,
rootConfig,
...
}: let
#
# GITLAB OPTIONS
#
gitlabOptions = {
stages = mkOption {
type = types.listOf types.str;
default = [];
# .pre and .post always exist
apply = val: [".pre"] ++ val ++ [".post"];
};
variables = mkUnsetOption {
type = types.attrsOf types.str;
description = '''';
};
};
in {
_file = ./pipeline.nix;
options =
{
nix = mkOption {
description = "Nix-CI config options for this pipeline";
type = types.submoduleWith {
modules = [pipelineConfigSubmodule];
specialArgs.rootConfig = rootConfig;
};
default = {};
};
finalConfig = mkOption {
description = "Final config of the pipeline";
internal = true;
type = types.attrs;
};
packages = mkOption {
description = "Final packages for use in CI";
internal = true;
type = types.attrsOf types.package;
};
# jobs are nested to make distinguishing them from other keys in the ci config easier
jobs = mkOption {
description = "Jobs for this pipeline";
type = types.attrsOf (types.submoduleWith {
modules = [jobSubmodule];
specialArgs = {
pipelineName = name;
pipelineConfig = config.nix;
};
});
default = {};
};
}
// gitlabOptions;
config = let
attrsToKeep = builtins.attrNames gitlabOptions;
in {
finalConfig =
(filterUnset (filterAttrs (n: _v: builtins.elem n attrsToKeep) config))
// mapAttrs (_name: value: value.finalConfig) config.jobs;
packages =
{
"gitlab-ci:pipeline:${name}" = pipe config.finalConfig [
builtins.toJSON
builtins.unsafeDiscardOutputDependency
builtins.unsafeDiscardStringContext
(toYaml "gitlab-ci-config.json")
];
"gitlab-ci:pipeline:${name}:pretty" = toYamlPretty "gitlab-ci-config.yml" config.finalConfig;
}
// mergeAttrsList (map (job: job.packages) (builtins.attrValues config.jobs));
};
};
in {
inherit pipelineSubmodule pipelineConfigSubmodule;
}

61
lib/impl/modules/root.nix Normal file
View file

@ -0,0 +1,61 @@
{
lib,
soonixSubmodule,
pipelineSubmodule,
...
}: let
inherit (lib) mkOption types;
in rec {
configSubmodule = {
options = {
soonix = mkOption {
description = "Configure the soonix '.gitlab-ci.yml' generation";
type = types.submodule soonixSubmodule;
default = {};
};
nixJobsByDefault = mkOption {
description = ''
Whether to transform all jobs to nix-configured jobs by default.
If false, you need to set `nix.enable` for each job you want to be transformed.
'';
type = types.bool;
default = true;
};
};
};
nixCiSubmodule = {config, ...}: {
options = {
config = mkOption {
description = "Configuration of Nix-GitLab-CI itself";
type = types.submodule configSubmodule;
default = {};
};
pipelines = mkOption {
description = "Defines all pipelines";
type = types.attrsOf (types.submoduleWith {
modules = [pipelineSubmodule];
specialArgs.rootConfig = config.config;
});
default = {};
};
packages = mkOption {
description = "Final packages for use in CI";
internal = true;
type = types.attrsOf types.package;
};
soonix = mkOption {
description = "Soonix config for .gitlab-ci.yml";
internal = true;
type = types.attrs;
};
};
config = {
packages = lib.fold (pipeline: acc: acc // pipeline) {} (
map (pipeline: pipeline.packages) (builtins.attrValues config.pipelines)
);
soonix = config.config.soonix.finalConfig;
};
};
}

View file

@ -0,0 +1,61 @@
{
lib,
cilib,
...
}: let
inherit (lib) mkOption types;
in {
soonixSubmodule = {config, ...}: {
options = {
componentVersion = mkOption {
description = "CI/CD component version. Also get's passed to inputs version";
type = types.str;
default = cilib.version;
};
componentUrl = mkOption {
description = "CI/CD component url";
type = types.str;
default = "gitlab.com/TECHNOFAB/nix-gitlab-ci/nix-gitlab-ci";
};
componentInputs = mkOption {
description = "Extra inputs to pass to the CI/CD component";
type = types.attrs;
default = {};
};
extraData = mkOption {
description = "Extra data to include in the .gitlab-ci.yml file";
type = types.attrs;
default = {};
};
finalConfig = mkOption {
internal = true;
type = types.attrs;
};
};
config.finalConfig = {
opts.format = "yaml";
hook = {
mode = "copy";
gitignore = false;
};
output = ".gitlab-ci.yml";
generator = "nix";
data =
cilib.helpers.deepMerge
{
include = [
{
component = "${config.componentUrl}@${config.componentVersion}";
inputs =
{
version = config.componentVersion;
}
// config.componentInputs;
}
];
}
config.extraData;
};
};
}