Compare commits

..

16 commits
v3.0.0 ... main

Author SHA1 Message Date
097f775cff Merge branch 'typo' into 'main'
docs: fix Soonix URL in README.md

See merge request TECHNOFAB/nix-gitlab-ci!16
2025-12-16 20:26:09 +01:00
asimon
139912d9c6 docs: fix Soonix URL in README.md 2025-12-16 19:12:06 +01:00
8f88a53b54
chore: bump version 2025-12-11 10:17:52 +01:00
555ae3de29
chore: update flakes 2025-12-05 20:21:26 +01:00
8eadfb56ba
fix(modules): fold was deprecated, replace with foldr 2025-12-05 20:16:37 +01:00
8a77208ebe
chore: bump version 2025-12-03 21:02:46 +01:00
1e9ddff300
fix(modules/job): fix variables with nix store paths getting dropped 2025-12-03 20:47:39 +01:00
59f8bd169a
chore: bump version 2025-12-02 15:12:28 +01:00
97fb4fafc3
fix(jobPatched): handle non-nix jobs correctly
fix mkJobPatched removing `cache` and `variables` from non-nix jobs

See !15 for more
2025-12-02 15:10:35 +01:00
1c9e7c77c5
chore: add test and docs for handling nix store paths in global variables 2025-12-02 15:09:27 +01:00
Skryta Istota
96e6fe59bf
ci: fix oci image used for dog fooding & forks 2025-12-02 14:31:27 +01:00
Skryta Istota
d0662e3185
fix(helpers): use builtin nix store location indicator 2025-12-02 14:30:54 +01:00
524bdf9cdc
chore: bump version 2025-11-13 21:44:28 +01:00
f5181b7b61
fix(sandbox_helper): fix comparisons, rename TMPDIR variable, add help
1. fixes comparisons with true for flag variables
2. renames TMPDIR to NGCI_TMPDIR so it doesn't interfere with the
   standardized TMPDIR var (and at some point accidentally deleting /tmp)
3. add small help message when invalid arg/param is passed
4. run `git add .` on copied git repo in /tmp so staged files stay
   staged there aswell
2025-11-13 21:40:24 +01:00
afe1e02310
fix(job): use unmodified job for mkJobRun
otherwise it tries to run "setup_nix_ci" etc. when running locally,
which doesn't make sense here
2025-11-13 21:39:38 +01:00
fa33f6e0b7
chore: alias original pipeline source & document component issue
Closes #27
2025-10-09 14:04:21 +02:00
16 changed files with 134 additions and 49 deletions

View file

@ -55,3 +55,5 @@ stages:
- build-images
- build
- trigger
variables:
NIX_CI_IMAGE: $CI_REGISTRY_IMAGE/nix-ci:$CI_COMMIT_SHORT_SHA

View file

@ -108,4 +108,4 @@ There is also `.#gitlab-ci:pipeline:<pipeline name>:job-deps:<name>` which gener
Some parts of this implementation are adapted/inspired from https://gitlab.com/Cynerd/gitlab-ci-nix
[docs-soonix]: https://nix-gitlab-ci.projects,tf/soonix "Soonix Integration"
[docs-soonix]: https://nix-gitlab-ci.projects.tf/soonix "Soonix Integration"

View file

@ -2,6 +2,13 @@
The CI/CD Component has some inputs which configure defaults for Nix GitLab CI.
!!! WARNING
If you get errors like `the component path is not supported` it might be related to
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/437996#note_1775337668).
See [here](https://gitlab.com/TECHNOFAB/nix-gitlab-ci/-/issues/27) for more.
## `version`
- Type: `string`

View file

@ -9,3 +9,14 @@ 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.
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.

12
flake.lock generated
View file

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1756542300,
"narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=",
"lastModified": 1764667669,
"narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d7600c775f877cd87b4f5a831c28aa94137377aa",
"rev": "418468ac9527e799809c900eda37cbff999199b6",
"type": "github"
},
"original": {
@ -37,11 +37,11 @@
},
"locked": {
"dir": "lib",
"lastModified": 1756370106,
"narHash": "sha256-l84ojcHuQWBwn4BRxQsMMfQpcq/Az/sHh/hSqFgVtyg=",
"lastModified": 1758738378,
"narHash": "sha256-NjzqdvQCDDdObEBH8x/vdhbdhrIB+N9E570uCdksGHY=",
"owner": "rensa-nix",
"repo": "core",
"rev": "9c1a29fa9ba7cbbb78b9e47eb8afbcd29303a3b4",
"rev": "abe19f9f13aff41de2b63304545c87d193d19ef4",
"type": "gitlab"
},
"original": {

View file

@ -1 +1 @@
3.0.0
3.1.2

View file

@ -50,7 +50,7 @@ in rec {
filterJobVariables = shouldContain: job:
concatMapAttrs (
name: value:
optionalAttrs ((hasInfix "/nix/store/" value) == shouldContain) {
optionalAttrs ((hasInfix builtins.storeDir value) == shouldContain) {
${name} = value;
}
)

View file

@ -11,13 +11,13 @@ in
pipelineName,
nixConfig,
}:
if ! nixConfig.enable
then job
else
(builtins.removeAttrs job ["variables" "cache"])
// (optionalAttrs nixConfig.enable (
(prependToBeforeScript ["source setup_nix_ci \"gitlab-ci:pipeline:${pipelineName}:job-deps:${key}\""] job)
// (prependToBeforeScript ["source setup_nix_ci \"gitlab-ci:pipeline:${pipelineName}:job-deps:${key}\""] job)
// (appendToAfterScript ["finalize_nix_ci"] job)
))
// optionalAttrs nixConfig.enable (
(let
// (let
variables =
(filterJobVariables false job)
// optionalAttrs nixConfig.enableRunnerCache {
@ -40,4 +40,3 @@ in
optionalAttrs (cache != []) {
inherit cache;
})
)

View file

@ -637,22 +637,22 @@ in rec {
// gitlabOptions;
config = let
attrsToKeep = builtins.attrNames gitlabOptions;
job = filterUnset (filterAttrs (n: _v: builtins.elem n attrsToKeep) config);
in {
finalConfig = cilib.mkJobPatched {
key = name;
job = filterUnset (filterAttrs (n: _v: builtins.elem n attrsToKeep) config);
nixConfig = config.nix;
inherit pipelineName;
inherit job pipelineName;
};
depsDrv = cilib.mkJobDeps {
key = name;
job = config.finalConfig;
nixConfig = config.nix;
inherit job;
};
runnerDrv = cilib.mkJobRun {
key = name;
job = config.finalConfig;
jobDeps = config.depsDrv;
inherit job;
};
packages = {
"gitlab-ci:pipeline:${pipelineName}:job-deps:${name}" = config.depsDrv;

View file

@ -4,7 +4,7 @@
pipelineSubmodule,
...
}: let
inherit (lib) mkOption types;
inherit (lib) mkOption types foldr;
in rec {
configSubmodule = {
options = {
@ -65,7 +65,7 @@ in rec {
};
};
config = {
packages = lib.fold (pipeline: acc: acc // pipeline) {} (
packages = foldr (pipeline: acc: acc // pipeline) {} (
map (pipeline: pipeline.packages) (builtins.attrValues config.pipelines)
);
soonix = config.config.soonix.finalConfig;

View file

@ -28,18 +28,19 @@ while [[ $# -gt 0 ]]; do
;;
*)
echo "Unknown option: $1" >&2
echo "use --include-dirty, --no-sandbox, --keep-tmp and --keep-env <ENV>" >&2
exit 1
;;
esac
done
if [ "$NO_SANDBOX" = false ]; then
if [ $NO_SANDBOX = false ]; then
echo "Running with simple sandboxing"
TMPDIR=$(mktemp -dt "nix-gitlab-ci.XXX")
if [ "$KEEP_TMP" = false ]; then
trap "rm -rf '$TMPDIR'" EXIT
NGCI_TMPDIR=$(mktemp -dt "nix-gitlab-ci.XXX")
if [ $KEEP_TMP = false ]; then
trap "rm -rf '$NGCI_TMPDIR'" EXIT
else
echo "Temp dir will be preserved at: $TMPDIR"
echo "Temp dir will be preserved at: $NGCI_TMPDIR"
fi
# check if dirty
@ -50,14 +51,15 @@ if [ "$NO_SANDBOX" = false ]; then
git diff --staged > "$DIRTY_PATCH"
trap "rm -f '$DIRTY_PATCH'" EXIT
fi
git clone . $TMPDIR
pushd $TMPDIR >/dev/null
if [[ ! -z "$DIRTY_PATCH" && "$INCLUDE_DIRTY" = true ]]; then
git clone . $NGCI_TMPDIR
pushd $NGCI_TMPDIR >/dev/null
if [[ ! -z "$DIRTY_PATCH" && $INCLUDE_DIRTY = true ]]; then
echo "Copying dirty changes..."
git apply "$DIRTY_PATCH" 2>/dev/null || echo "Failed to copy dirty changes"
git add . # required so the files are staged again
fi
echo "Running job in $TMPDIR"
echo "Running job in $NGCI_TMPDIR"
env -i $(
if [[ -n "$KEEP_ENV" ]]; then
IFS=',' read -ra VARS <<< "$KEEP_ENV"

View file

@ -10,6 +10,7 @@ in
# the child pipeline can then use the built images to test them
extraData = {
stages = ["build-images" "build" "trigger"];
variables.NIX_CI_IMAGE = "$CI_REGISTRY_IMAGE/nix-ci:$CI_COMMIT_SHORT_SHA";
"build:image" = {
stage = "build-images";
parallel.matrix = [

30
nix/repo/flake.lock generated
View file

@ -3,11 +3,11 @@
"devshell-lib": {
"locked": {
"dir": "lib",
"lastModified": 1755673398,
"narHash": "sha256-51MmR+Eo1+bKDd/Ss77wwTqi4yAR2xgmyCSEbKWSpj0=",
"lastModified": 1758204313,
"narHash": "sha256-ainbY0Oajb1HMdvy+A8QxF/P5qwcbEzJGEY5pzKdDdc=",
"owner": "rensa-nix",
"repo": "devshell",
"rev": "e76bef387e8a4574f9b6d37b1a424e706491af08",
"rev": "7d0c4bc78d9f017a739b0c7eb2f4e563118353e6",
"type": "gitlab"
},
"original": {
@ -20,11 +20,11 @@
"nixmkdocs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1757055638,
"narHash": "sha256-KHYSkEreFe4meXzSdEbknC/HwaQSNClQkc8vzHlAsMM=",
"lastModified": 1763481845,
"narHash": "sha256-Bp0+9rDmlPWMcnKqGx+BG4+o5KO8FuDAOvXRnXrm3Fo=",
"owner": "TECHNOFAB",
"repo": "nixmkdocs",
"rev": "7840a5febdbeaf2da90babf6c94b3d0929d2bf74",
"rev": "73d59093df94a894d25bc4bf71880b6f00faa62f",
"type": "gitlab"
},
"original": {
@ -37,11 +37,11 @@
"nixtest-lib": {
"locked": {
"dir": "lib",
"lastModified": 1756812148,
"narHash": "sha256-0g8KNk4zoLApA51PBHOWqPLRYpprjrQuSzNCjfBQgu8=",
"lastModified": 1759340550,
"narHash": "sha256-EH9heYb/nHHzCpUGQGqVQnuyVGQ7D6MVMgJmzNvvmJ8=",
"owner": "TECHNOFAB",
"repo": "nixtest",
"rev": "5741109cc9ec2b6d41b56abd3f5bc51ed7a9a228",
"rev": "5a7053afcbb211b9cf8fe87f7892bb9f6b76b678",
"type": "gitlab"
},
"original": {
@ -63,11 +63,11 @@
"soonix-lib": {
"locked": {
"dir": "lib",
"lastModified": 1756797658,
"narHash": "sha256-4rkyP4oaoqG/FFVL7W8U+8hGer4tOBPff/2SeN5tJYQ=",
"lastModified": 1763323017,
"narHash": "sha256-MJyg37d+VMfRoFiVUj16FW+zkEwQXbgK9LoFF/SHoxA=",
"owner": "TECHNOFAB",
"repo": "soonix",
"rev": "3baef660cf8b87391d475a0455dd66fae0e60008",
"rev": "078034b01e4eaf1f9436d46721f7cbe0d96eb8b4",
"type": "gitlab"
},
"original": {
@ -80,11 +80,11 @@
"treefmt-nix": {
"flake": false,
"locked": {
"lastModified": 1756662192,
"narHash": "sha256-F1oFfV51AE259I85av+MAia221XwMHCOtZCMcZLK2Jk=",
"lastModified": 1762938485,
"narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "1aabc6c05ccbcbf4a635fb7a90400e44282f61c4",
"rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"type": "github"
},
"original": {

View file

@ -62,6 +62,7 @@ nix-ci:build:
|| NIX_CI_PIPELINE_NAME="$CI_PIPELINE_SOURCE";
fi
echo "NIX_CI_GENERATED_PIPELINE_NAME=$NIX_CI_PIPELINE_NAME" >> trigger.env
echo "ORIGINAL_CI_PIPELINE_SOURCE=$CI_PIPELINE_SOURCE" >> trigger.env
# inheritance of pipeline variables is a bit weird, so explicitly override them
# (ctx: setting any of these in the project variables would only apply correctly
# in this pipeline, not the child pipeline, instead weirdly enough the default

View file

@ -64,6 +64,22 @@
nixConfig.enable = false;
};
}
{
name = "jobPatched nix disabled with variables and cache";
expected = {
variables."HELLO" = "world";
cache = [{key = "example";}];
};
actual = mkJobPatched {
key = "test";
pipelineName = "test";
job = {
variables."HELLO" = "world";
cache = [{key = "example";}];
};
nixConfig.enable = false;
};
}
{
name = "jobPatched without runner cache";
expected = {
@ -129,7 +145,7 @@
# sh
''
set -euo pipefail
${ntlib.helpers.path [pkgs.jq pkgs.gnugrep pkgs.coreutils]}
${ntlib.helpers.path (with pkgs; [jq gnugrep coreutils])}
echo "two keys, one json one pretty"
jq 'keys | length == 2' "${pipeline}" | grep -q true
echo "key[0] is exactly 'gitlab-ci:pipeline:test'"
@ -145,10 +161,13 @@
'';
}
{
name = "handle store paths in variables";
name = "ignore store paths in variables with nix disabled";
expected = {
stages = ["test"];
test.stage = "test";
test = {
stage = "test";
variables."TEST" = "${pkgs.hello}";
};
};
actual =
(mkPipeline {
@ -163,6 +182,28 @@
};
}).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 = {
variables = {
HELLO = "world";
CURL = toString pkgs.curl;
};
};
actual =
(mkPipeline {
name = "test";
nixConfig.enable = true;
pipeline = {
variables = {
HELLO = "world";
CURL = toString pkgs.curl;
};
jobs = {};
};
}).finalConfig;
}
];
};
}

View file

@ -77,6 +77,27 @@
assert_file_contains ${package} '"EXAMPLE":"/nix/store/.*-hello-.*"'
'';
}
{
name = "correctly inject variables containing nix store paths at runtime";
type = "script";
script = let
package =
(cilib.mkCI {
pipelines."test".jobs."test" = {
stage = ".pre";
variables.EXAMPLE = "${pkgs.hello}";
script = [];
};
}).packages."gitlab-ci:pipeline:test:job-deps:test";
in
# sh
''
${ntlib.helpers.path [pkgs.gnugrep]}
${ntlib.helpers.scriptHelpers}
assert_file_contains ${package} 'export PATH=":$PATH";'
assert_file_contains ${package} 'export EXAMPLE="/nix/store/.*-hello-.*"'
'';
}
];
};
}