Compare commits

..

1 commit

Author SHA1 Message Date
Skryta Istota
bdbc12771f Merge branch 'fix-job-patch' into 'main'
fix: weird jobs patching

See merge request TECHNOFAB/nix-gitlab-ci!15
2025-12-02 14:32:22 +01:00
7 changed files with 200 additions and 151 deletions

View file

@ -9,14 +9,3 @@ This project provides a Nix flake module that allows you to generate your `.gitl
- **Modularity:** Define and manage your CI configurations in a structured and modular way using Nix modules, making it easier to share and reuse CI logic across multiple projects. - **Modularity:** Define and manage your CI configurations in a structured and modular way using Nix modules, making it easier to share and reuse CI logic across multiple projects.
This documentation will guide you through setting up and using Nix GitLab CI for your projects. This documentation will guide you through setting up and using Nix GitLab CI for your projects.
## Warnings
To save you from frantically searching these docs if something doesn't work as expected, here are the most important warnings ;)
!!! warning
Do not put Nix store paths into global/pipeline variables. They will simply be passed through,
resulting in bad portability (if two runners have different archs for example, one cannot find the path).
If you need any Nix store path in env variables, always do it on the job level, there
it will automatically be computed at runtime, thus will always work no matter which runner it runs on.

View file

@ -1 +1 @@
3.1.0 3.0.1

View file

@ -3,7 +3,7 @@
helpers, helpers,
}: let }: let
inherit (lib) toList optionalAttrs optional; inherit (lib) toList optionalAttrs optional;
inherit (helpers) prependToBeforeScript appendToAfterScript filterJobVariables; inherit (helpers) prependToBeforeScript appendToAfterScript;
in in
{ {
key, key,
@ -11,32 +11,28 @@ in
pipelineName, pipelineName,
nixConfig, nixConfig,
}: }:
if ! nixConfig.enable if ! nixConfig.enable then job else
then job (builtins.removeAttrs job [ "variables" "cache" ])
else // (prependToBeforeScript [ "source setup_nix_ci \"gitlab-ci:pipeline:${pipelineName}:job-deps:${key}\"" ] job)
(builtins.removeAttrs job ["variables" "cache"]) // (appendToAfterScript [ "finalize_nix_ci" ] job)
// (prependToBeforeScript ["source setup_nix_ci \"gitlab-ci:pipeline:${pipelineName}:job-deps:${key}\""] job) // (let
// (appendToAfterScript ["finalize_nix_ci"] job) variables = job.variables or {} //
// (let optionalAttrs nixConfig.enableRunnerCache {
variables = NIX_CI_CACHE_STRATEGY = "runner";
(filterJobVariables false job) };
// optionalAttrs nixConfig.enableRunnerCache { in
NIX_CI_CACHE_STRATEGY = "runner"; # filter empty variables
}; optionalAttrs (variables != {}) {
in inherit variables;
# filter empty variables })
optionalAttrs (variables != {}) { // (let
inherit variables; cache = (toList (job.cache or [])) ++
}) (optional nixConfig.enableRunnerCache {
// (let key = nixConfig.runnerCacheKey;
cache = paths = [ ".nix-cache/" ];
(toList (job.cache or [])) });
++ (optional nixConfig.enableRunnerCache { in
key = nixConfig.runnerCacheKey; # filter empty cache
paths = [".nix-cache/"]; optionalAttrs (cache != []) {
}); inherit cache;
in })
# filter empty cache
optionalAttrs (cache != []) {
inherit cache;
})

View file

@ -646,7 +646,7 @@ in rec {
}; };
depsDrv = cilib.mkJobDeps { depsDrv = cilib.mkJobDeps {
key = name; key = name;
inherit job; job = config.finalConfig;
nixConfig = config.nix; nixConfig = config.nix;
}; };
runnerDrv = cilib.mkJobRun { runnerDrv = cilib.mkJobRun {

View file

@ -1,5 +1,5 @@
{inputs, ...}: let {inputs, ...}: let
inherit (inputs) cilib pkgs; inherit (inputs) cilib;
in in
cilib.mkCI { cilib.mkCI {
config.soonix = { config.soonix = {
@ -58,25 +58,9 @@ in
}; };
}; };
pipelines."default" = { pipelines."default" = {
stages = ["check" "test" "build" "deploy"]; stages = ["test" "build" "deploy"];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
jobs = { jobs = {
"check" = {
stage = "check";
script = [
"set -euo pipefail"
"echo EXAMPLE=$EXAMPLE CURL=$CURL SAMPLE=$SAMPLE HELLO=$HELLO"
];
variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
};
};
"test" = { "test" = {
nix.deps = with pkgs; [coreutils nix];
stage = "test"; stage = "test";
script = [ script = [
"nix run .#tests -- --junit=junit.xml" "nix run .#tests -- --junit=junit.xml"
@ -89,7 +73,6 @@ in
}; };
"docs" = { "docs" = {
stage = "build"; stage = "build";
nix.deps = with pkgs; [coreutils nix];
script = [ script = [
# sh # sh
'' ''

View file

@ -56,26 +56,28 @@
} }
{ {
name = "jobPatched nix disabled"; name = "jobPatched nix disabled";
expected = {};
actual = mkJobPatched {
key = "test";
pipelineName = "test";
job = {};
nixConfig.enable = false;
};
}
{
name = "jobPatched nix disabled with variables and cache";
expected = { expected = {
variables."HELLO" = "world"; cache = {
cache = [{key = "example";}]; name = "some";
paths = [ "this" ];
};
variables = {
BASH = toString pkgs.bash;
TEST = "work";
};
}; };
actual = mkJobPatched { actual = mkJobPatched {
key = "test"; key = "test";
pipelineName = "test"; pipelineName = "test";
job = { job = {
variables."HELLO" = "world"; cache = {
cache = [{key = "example";}]; name = "some";
paths = [ "this" ];
};
variables = {
BASH = toString pkgs.bash;
TEST = "work";
};
}; };
nixConfig.enable = false; nixConfig.enable = false;
}; };
@ -83,13 +85,30 @@
{ {
name = "jobPatched without runner cache"; name = "jobPatched without runner cache";
expected = { expected = {
after_script = ["finalize_nix_ci"]; after_script = [ "finalize_nix_ci" ];
before_script = ["source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\""]; before_script = [ "source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\"" ];
variables = {
BASH = toString pkgs.bash;
TEST = "work";
};
cache = [{
name = "some";
paths = [ "this" ];
}];
}; };
actual = mkJobPatched { actual = mkJobPatched {
key = "test"; key = "test";
pipelineName = "test"; pipelineName = "test";
job = {}; job = {
cache = {
name = "some";
paths = [ "this" ];
};
variables = {
BASH = toString pkgs.bash;
TEST = "work";
};
};
nixConfig = { nixConfig = {
enable = true; enable = true;
enableRunnerCache = false; enableRunnerCache = false;
@ -99,20 +118,34 @@
{ {
name = "jobPatched with runner cache"; name = "jobPatched with runner cache";
expected = { expected = {
after_script = ["finalize_nix_ci"]; after_script = [ "finalize_nix_ci" ];
before_script = ["source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\""]; before_script = [ "source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\"" ];
cache = [ cache = [{
{ name = "some";
key = "test"; paths = [ "this" ];
paths = [".nix-cache/"]; }{
} key = "test";
]; paths = [ ".nix-cache/" ];
variables."NIX_CI_CACHE_STRATEGY" = "runner"; }];
variables = {
NIX_CI_CACHE_STRATEGY = "runner";
BASH = toString pkgs.bash;
TEST = "work";
};
}; };
actual = mkJobPatched { actual = mkJobPatched {
key = "test"; key = "test";
pipelineName = "test"; pipelineName = "test";
job = {}; job = {
cache = {
name = "some";
paths = [ "this" ];
};
variables = {
BASH = toString pkgs.bash;
TEST = "work";
};
};
nixConfig = { nixConfig = {
enable = true; enable = true;
enableRunnerCache = true; enableRunnerCache = true;
@ -161,48 +194,110 @@
''; '';
} }
{ {
name = "ignore store paths in variables with nix disabled"; name = "handle store paths in variables without nix config";
expected = {
stages = ["test"];
test = {
stage = "test";
variables."TEST" = "${pkgs.hello}";
};
};
actual =
(mkPipeline {
name = "test";
nixConfig.enable = false;
pipeline = {
stages = ["test"];
jobs.test = {
stage = "test";
variables."TEST" = "${pkgs.hello}";
};
};
}).finalConfig;
}
{
# it doesn't make much sense to have any nix store path in variables, but we ignore it for global variables
name = "ignore store paths in global variables";
expected = { expected = {
stages = [ "test" ];
variables = { variables = {
HELLO = "world"; EXAMPLE = "empty";
CURL = toString pkgs.curl; CURL = toString pkgs.curl;
}; };
}; test = {
actual = stage = "test";
(mkPipeline { before_script = [ "./init" ];
name = "test"; script = [ "echo Hello World!" ];
nixConfig.enable = true; after_script = [ "./clean" ];
pipeline = { cache = {
variables = { key = "simple";
HELLO = "world"; paths = [ "~/random/" ];
CURL = toString pkgs.curl;
};
jobs = {};
}; };
}).finalConfig; variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
};
};
};
actual = (mkPipeline {
name = "test";
nixConfig.enable = false;
pipeline = {
stages = [ "test" ];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
jobs.test = {
stage = "test";
before_script = [ "./init" ];
script = [ "echo Hello World!" ];
after_script = [ "./clean" ];
cache = {
key = "simple";
paths = [ "~/random/" ];
};
variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
};
};
};
}).finalConfig;
}
{
name = "handle store paths in variables with nix config";
expected = {
stages = [ "test" ];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
test = {
stage = "test";
before_script = [ "source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\"" "./init" ];
script = [ "echo Hello World!" ];
after_script = [ "./clean" "finalize_nix_ci" ];
cache = [{
key = "simple";
paths = [ "~/random/" ];
}{
key = "random";
paths = [ ".nix-cache/" ];
}];
variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
NIX_CI_CACHE_STRATEGY = "runner";
};
};
};
actual = (mkPipeline {
name = "test";
nixConfig = {
enable = true;
enableRunnerCache = true;
runnerCacheKey = "random";
};
pipeline = {
stages = [ "test" ];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
jobs.test = {
stage = "test";
before_script = [ "./init" ];
script = [ "echo Hello World!" ];
after_script = [ "./clean" ];
cache = {
key = "simple";
paths = [ "~/random/" ];
};
variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
};
};
};
}).finalConfig;
} }
]; ];
}; };

View file

@ -10,17 +10,9 @@
simplePipeline = cilib.mkCI { simplePipeline = cilib.mkCI {
pipelines."test" = { pipelines."test" = {
stages = ["test"]; stages = ["test"];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
jobs."test" = { jobs."test" = {
stage = "test"; stage = "test";
script = ["echo hello world"]; script = ["echo hello world"];
variables = {
SAMPLE = "working";
HELLO = toString pkgs.hello;
};
}; };
}; };
}; };
@ -38,29 +30,21 @@
(cilib.mkCI {}).packages; (cilib.mkCI {}).packages;
} }
{ {
name = "simple pipeline final config"; name = "simple pipeline";
expected = { expected = {
stages = [".pre" "test" ".post"]; stages = [".pre" "test" ".post"];
variables = {
EXAMPLE = "empty";
CURL = toString pkgs.curl;
};
"test" = { "test" = {
image = "$NIX_CI_IMAGE"; image = "$NIX_CI_IMAGE";
stage = "test"; stage = "test";
before_script = ["source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\""]; before_script = ["source setup_nix_ci \"gitlab-ci:pipeline:test:job-deps:test\""];
script = ["echo hello world"]; script = ["echo hello world"];
after_script = ["finalize_nix_ci"]; after_script = ["finalize_nix_ci"];
variables = {
SAMPLE = "working";
#HELLO = toString pkgs.hello;
};
}; };
}; };
actual = simplePipeline.pipelines."test".finalConfig; actual = simplePipeline.pipelines."test".finalConfig;
} }
{ {
name = "simple pipeline json"; name = "simple pipeline yaml";
type = "script"; type = "script";
script = let script = let
package = simplePipeline.packages."gitlab-ci:pipeline:test"; package = simplePipeline.packages."gitlab-ci:pipeline:test";
@ -72,23 +56,25 @@
assert_file_contains ${package} 'gitlab-ci:pipeline:test:job-deps:test' assert_file_contains ${package} 'gitlab-ci:pipeline:test:job-deps:test'
assert_file_contains ${package} 'finalize_nix_ci' assert_file_contains ${package} 'finalize_nix_ci'
assert_file_contains ${package} 'echo hello world' assert_file_contains ${package} 'echo hello world'
assert_file_contains ${package} '"EXAMPLE":"empty"'
assert_file_contains ${package} '"SAMPLE":"working"'
assert_file_contains ${package} '"CURL":"/nix/store/.*-curl-.*"'
''; '';
} }
{ {
name = "simple pipeline deps drv"; name = "dont fail on store paths";
type = "script"; type = "script";
script = let script = let
package = simplePipeline.packages."gitlab-ci:pipeline:test:job-deps:test"; package =
(cilib.mkCI {
pipelines."test" = {
variables.EXAMPLE = "${pkgs.hello}";
};
}).packages."gitlab-ci:pipeline:test";
in in
# sh # sh
'' ''
${ntlib.helpers.path [pkgs.gnugrep]} ${ntlib.helpers.path [pkgs.gnugrep]}
${ntlib.helpers.scriptHelpers} ${ntlib.helpers.scriptHelpers}
assert_file_contains ${package} ':$PATH' assert_file_contains ${package} '[".pre",".post"]'
assert_file_contains ${package} 'HELLO="/nix/store/.*-hello-.*"' assert_file_contains ${package} '"EXAMPLE":"/nix/store/.*-hello-.*"'
''; '';
} }
]; ];