Skip to content

Implement module system with composable CI modules

Horizon Bot requested to merge feature/implement-module-system-v2 into master

Summary

This MR implements a comprehensive module system for gitlab.ci that enables composing CI configuration from multiple reusable modules. Includes four built-in modules with generic validator support and explicit stage ordering.

Module System Features

  • gitlab.ci.modules option accepts a list of modules
  • Modules are evaluated with lib.evalModules and automatically merged
  • Stage ordering with priority hints - Stages sorted by configurable priority values
  • flake configuration option - Explicit flake = self for modules that need access to all flake outputs
  • Jobs are merged (later modules can override earlier ones)
  • Direct stages/jobs and modules options work together seamlessly

Built-in Modules

All modules are exported via inputs.gitlab-ci.modules.gitlab-ci.<name>:

1. omnix - Omnix build CI jobs

Options:

  • enable - Enable omnix jobs
  • systems - List of systems to build for
  • flakes - List of flake paths to run on
  • stage - CI stage name (default: "build")

Generates parallel matrix jobs for building across systems/flakes using om ci run.

2. cachix - Cachix push CI jobs

Options:

  • enable - Enable cachix jobs
  • cache - Cachix cache name
  • systems - List of systems
  • flakes - List of flake paths
  • stage - CI stage name (default: "publish")

Pushes builds to cachix on protected branches only.

3. discover - Auto-discover flake outputs

Options:

  • enable - Enable discover jobs
  • systems - List of systems to generate jobs for (null = all)

Auto-discovers packages, checks, devShells, and nixosConfigurations from the flake and generates CI jobs. Requires flake = self to be set in gitlab.ci config.

4. validate - Generic git diff validators

Options:

  • enable - Enable validation jobs
  • stage - Default stage for validators (default: "validate")
  • validators - Attribute set of validator configurations

Each validator can specify:

  • enable - Enable this validator
  • paths - List of paths to validate
  • command - Command to run (may modify files)
  • files - Files/patterns to check for changes
  • errorMessage - Error message on validation failure
  • stage - Override default stage

Example validators:

  • flake-lock - Ensures flake.lock is up to date
  • format - Ensures code is formatted
  • lint - Ensures linting passes
  • Any custom command + git diff validation

Stage Ordering

Stages are automatically sorted by priority:

Default priorities:

  • validate = 10
  • build = 20
  • test = 30
  • publish = 40
  • deploy = 50
  • Unknown stages = 100

Customizable via stageOrder option to add custom stages or reorder defaults.

Usage Example

{ self, inputs, ... }: {
  imports = [ inputs.gitlab-ci.flakeModule ];

  perSystem = { ... }: {
    gitlab.ci = {
      enable = true;
      flake = self;  # Required for discover module

      imports = [
        inputs.gitlab-ci.modules.gitlab-ci.omnix
        inputs.gitlab-ci.modules.gitlab-ci.cachix
        inputs.gitlab-ci.modules.gitlab-ci.discover
        inputs.gitlab-ci.modules.gitlab-ci.validate
      ];

      omnix = {
        enable = true;
        systems = [ "x86_64-linux" "aarch64-darwin" ];
        flakes = [ "." ];
        stage = "build";
      };

      cachix = {
        enable = true;
        cache = "my-cache";
        systems = [ "x86_64-linux" ];
      };

      discover = {
        enable = true;
        systems = [ "x86_64-linux" ];
      };

      validate = {
        enable = true;
        validators = {
          flake-lock = {
            enable = true;
            paths = [ "." ];
            command = "nix flake lock";
            files = [ "flake.lock" ];
            errorMessage = "flake.lock is not up to date. Run: nix flake lock";
          };
        };
      };

      # Optional: customize stage ordering
      stageOrder = {
        validate = 10;
        build = 20;
        test = 30;
        publish = 40;
      };
    };
  };
}

Testing

  • Golden tests: test/module-test/ demonstrates all modules with golden YAML snapshot
  • Stage ordering: Verified stages run in correct order (validate → build → publish)
  • Import-tree pattern: Test uses import-tree for modular configuration

Benefits

  1. Composability - Mix and match CI modules as needed
  2. Reusability - Common patterns extracted into modules
  3. Extensibility - Projects can ship their own CI modules
  4. Predictability - Explicit stage ordering ensures correct execution order
  5. Flexibility - Generic validator system supports any command + git diff check
  6. Type Safety - Full NixOS module system with options/types
  7. Discoverability - nix flake show lists available modules

🤖 Generated with Claude Code

Edited by Horizon Bot

Merge request reports