diff options
| author | seth <[email protected]> | 2023-12-25 04:35:25 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-12-25 09:35:25 +0000 |
| commit | ee728efb75096431bb94f746d990f2dc786b0be2 (patch) | |
| tree | 2c8c01c29047985959c2f396c5fe0c4fe6644840 | |
| parent | c28ea3d40d1136ae644d560bcceb20a89fb7d9ff (diff) | |
| -rw-r--r-- | .github/workflows/ci.yaml | 4 | ||||
| -rw-r--r-- | .github/workflows/example.yaml | 3 | ||||
| -rw-r--r-- | README.md | 107 | ||||
| -rw-r--r-- | lib.nix | 98 | ||||
| -rw-r--r-- | module.nix | 99 | ||||
| -rw-r--r-- | test/lib/flake.nix | 39 | ||||
| -rw-r--r-- | test/module/flake.nix | 12 |
7 files changed, 206 insertions, 156 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7468b02..f4a5e3e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: for dir in "lib" "module"; do pushd test/"$dir" - echo "$dir=$(nix eval --show-trace --json .#githubWorkflow.matrix)" >> "$GITHUB_OUTPUT" + echo "$dir=$(nix eval --show-trace --json .#workflowMatrix)" >> "$GITHUB_OUTPUT" popd done @@ -37,6 +37,7 @@ jobs: needs: eval strategy: + fail-fast: false matrix: ${{ fromJSON(needs.eval.outputs.lib-matrix) }} name: Build (lib/${{ matrix.attr }}) @@ -70,6 +71,7 @@ jobs: needs: eval strategy: + fail-fast: false matrix: ${{ fromJSON(needs.eval.outputs.module-matrix) }} name: Build (module/${{ matrix.attr }}) diff --git a/.github/workflows/example.yaml b/.github/workflows/example.yaml index 0c214e9..3405f41 100644 --- a/.github/workflows/example.yaml +++ b/.github/workflows/example.yaml @@ -22,12 +22,13 @@ jobs: run: | set -eu - echo "matrix=$(nix eval --show-trace --json .#githubWorkflow.matrix)" >> "$GITHUB_OUTPUT" + echo "matrix=$(nix eval --show-trace --json .#workflowMatrix)" >> "$GITHUB_OUTPUT" build: needs: eval strategy: + fail-fast: false matrix: ${{ fromJSON(needs.eval.outputs.matrix) }} name: Build (${{matrix.attr}}) @@ -1,91 +1,100 @@ # nix2workflow - + [](https://flakehub.com/flake/getchoo/nix2workflow) -nix2workflow is a library for generating github matrices from regular nix flake outputs. +nix2workflow is a library for generating GitHub matrices from nix flake outputs. -## usage +## Usage -we offer both a standard library for use in any flake, along with +We offer both a standard library for use in any flake, along with a [flake-parts](https://flake.parts/) module for easier integration. -you can find an example workflow for use in your own project in +You can find an example workflow for use in your own project in [./.github/workflows/example.yaml](./.github/workflows/example.yaml). -### flake module +### Flake module -a basic setup might look like this. please see the [module](./module.nix) +A basic setup might look like this. Please see the [module](./module.nix) for all options ```nix -{ - imports = [nix2workflow.flakeModule]; +{self, ...}: { + imports = [ nix2workflow.flakeModule ]; - githubWorkflowGenerator = { - outputs = [ - "checks" - "devShells" - "nixosConfigurations" - "packages" - ]; + nix2workflow = { + # this will automatically build all standard outputs in self + root = self; overrides = { - checks.systems = ["x86_64-linux"]; + checks.systems = [ "x86_64-linux" ]; }; }; } ``` -a full example can be found in [./test/module/flake.nix](./test/module/flake.nix) +A full example can be found in [./test/module/flake.nix](./test/module/flake.nix) -### library +### Library -the regular library will have a more complicated setup, though +The regular library will have a more complicated setup, though it also allows using lower level functions and has no restrictions on what flake outputs are used. ```nix { - githubworkflow = let - workflow = nix2workflow.lib {inherit self;}; - outputs = [ - "checks" - "devShells" - "nixosConfigurations" - "packages" - ]; - in { - matrix.include = lib.concatLists ( - map ( - output: - workflow.mkMatrix { - inherit output; - # you can also specify what systems to build each output for - systems = ["x86_64-linux" "aarch64-darwin"]; - } - ) - outputs + workflowMatrix = let + platforms = { + x86_64-linux = { + os = "ubuntu-latest"; + arch = "x64"; + }; + + x86_64-darwin = { + os = "macos-latest"; + arch = "x64"; + }; + }; + + inherit (nix2workflow.lib { inherit platforms; }) mkMatrix; + + jobs = lib.flatten ( + (mkMatrix { + root = self; + output = "packages"; + }) + + (mkMatrix { + root = self; + output = "checks"; + systems = [ "x86_64-linux" ]; + }) ); + in { + include = jobs; }; } ``` -you can see a full example in [./test/lib/flake.nix](./test/lib/flake.nix) +You can see a full example in [./test/lib/flake.nix](./test/lib/flake.nix) -### in workflows +### In workflows -when the matrix is imported, a few variables with added to the `matrix` context. -these can allow you to customize your workflow based on what packages are building - +When the matrix is imported, a few variables with added to the `matrix` context. +These can allow you to customize your workflow based on what packages are building - such as enabling QEMU when building for aarch64 | name | use | | --- | --- | -| `os` | the operating system of the current output. usually `ubuntu-latest` or `macos-latest` | -| `arch` | the architecture of the current output. will be `aarch64` or `x64` | -| `attr` | the flake attribute of the current output (can really be anything) | +| `os` | The operating system of the current output. Usually `ubuntu-latest` or `macos-latest` | +| `arch` | The architecture of the current output. Will be `aarch64` or `x64` | +| `attr` | The flake attribute of the current output (can really be anything). + Note that you will still need to prefix this with the `root` attribute if set (i.e. `.#hydraJobs.${{ matrix.attrr }}`) | -## related projects +## Related projects - [nix-community/nix-github-actions](https://github.com/nix-community/nix-github-actions/) - - this is the primary inspiration for this project - and i believe also one of the first - projects to attempt this, so kudos! i just wanted a more opionated and expandable approach :) + - This is the primary inspiration for this project - and I believe also one of the first + projects to attempt this, so kudos! + - [nix-community/nix-eval-jobs](https://github.com/nix-community/nix-eval-jobs) + - I liked the idea of using `hydraJobs` (and possibly others) on GitHub Actions, and + thought it might be fun to make a direct translation of these attributes in pure nix @@ -1,80 +1,72 @@ -lib: { - self, - platforms ? { - "x86_64-linux" = { +lib: {platforms ? null}: let + defaultPlatforms = { + x86_64-linux = { os = "ubuntu-latest"; arch = "x64"; }; - "aarch64-linux" = { + aarch64-linux = { os = "ubuntu-latest"; arch = "aarch64"; }; - "x86_64-darwin" = { + x86_64-darwin = { os = "macos-latest"; arch = "x64"; }; - }, - ... -}: let + }; + platforms' = - platforms - // { - fallback = lib.warn "an output in the job matrix is not supported!" { - os = null; - arch = null; - }; - }; + if platforms != null + then platforms + else defaultPlatforms; + + fallback = lib.warn "an output in the job matrix is not supported!" { + os = null; + arch = null; + }; - mkMatrixMulti = systems: output: + platformNames = lib.attrNames platforms'; + + findSystem = deriv: deriv.system or deriv.pkgs.system or deriv.activationPackage.system; +in { + mkMatrix = { + root, + output, + systems ? platformNames, + }: lib.flatten ( lib.mapAttrsToList ( system: lib.mapAttrsToList ( attr: _: { - inherit (platforms'.${system} or platforms'.fallback) arch os; + inherit (platforms'.${system} or fallback) arch os; attr = "${output}.${system}.${attr}"; } ) ) - (lib.getAttrs systems self.${output}) + (lib.filterAttrs (system: _: lib.elem system systems) root.${output}) ); - mkMatrixFlat = { + mkMatrix' = { + root, output, - suffix ? "", + systems ? platformNames, }: - lib.mapAttrsToList ( - attr: deriv: { - inherit (platforms'.${deriv.pkgs.system} or platforms'.fallback) os arch; - attr = "${output}.${attr}${suffix}"; - } - ) - self.${output}; -in { - inherit - mkMatrixMulti - mkMatrixFlat - ; - - mkMatrix = { - output, - systems ? (builtins.attrNames platforms), - }: let - systemMatrix = mkMatrixFlat { - inherit output; - suffix = ".config.system.build.toplevel"; - }; - in - { - "nixosConfigurations" = systemMatrix; - "darwinConfigurations" = systemMatrix; - "homeConfigurations" = mkMatrixFlat { - inherit output; - suffix = ".activationPackage"; - }; - } - .${output} - or (mkMatrixMulti systems output); + lib.flatten ( + lib.mapAttrsToList ( + attr: deriv: let + system = findSystem deriv; + in { + inherit (platforms'.${system} or fallback) arch os; + attr = "${output}.${attr}"; + } + ) + ( + lib.filterAttrs ( + _: deriv: builtins.elem (findSystem deriv) systems + ) + root.${output} + ) + ); } @@ -4,7 +4,7 @@ workflowLib': { self, ... }: let - cfg = config.githubWorkflowGenerator; + cfg = config.nix2workflow; inherit (lib) @@ -12,24 +12,24 @@ workflowLib': { concatLists elem filter + filterAttrs + literalExpression + mapAttrsToList mdDoc mkOption - literalExpression + recursiveUpdate types ; - workflowLib = workflowLib' { - inherit self; - inherit (cfg) platforms; - }; + workflowLib = workflowLib' {inherit (cfg) platforms;}; + inherit (workflowLib) mkMatrix mkMatrix'; supportedOutputs = [ - "apps" "checks" "devShells" + "nixosConfigurations" "darwinConfigurations" "homeConfigurations" - "nixosConfigurations" "packages" ]; @@ -61,45 +61,66 @@ workflowLib': { }; }; - unfilteredJobs = concatLists ( - map ( - output: - workflowLib.mkMatrix ( - {inherit output;} // cfg.overrides.${output} or {} - ) + jobs = concatLists ( + mapAttrsToList ( + output: value: let + common = + recursiveUpdate + { + root = cfg.output; + inherit output; + } + (cfg.overrides.${output} or {}); + + flat = mkMatrix' common; + multi = mkMatrix common; + in + { + # TODO: maybe make this configurable? or follow flake-schemas? + # these are known "flat" values + "nixosConfigurations" = flat; + "darwinConfigurations" = flat; + "homeConfigurations" = flat; + } + .${output} + or multi ) - cfg.outputs + (filterAttrs (output: _: elem output supportedOutputs) cfg.output) ); in { options = { - githubWorkflowGenerator = { - outputs = mkOption { - description = mdDoc "outputs to include in workflow"; - type = types.listOf types.str; - default = filter (output: elem output supportedOutputs) (attrNames self); + nix2workflow = { + output = mkOption { + description = mdDoc "Root attribute for CI jobs"; + type = types.lazyAttrsOf types.raw; + default = self; + example = literalExpression "hydraJobs"; }; platforms = mkOption { description = mdDoc '' an attrset that can map a nix system to an architecture and os supported by github ''; - type = types.attrsOf (types.submodule platformMap); - default = { - "x86_64-linux" = { - os = "ubuntu-latest"; - arch = "x64"; - }; + type = types.nullOr (types.attrsOf (types.submodule platformMap)); + default = null; + example = literalExpression '' + { + "x86_64-linux" = { + os = "ubuntu-latest"; + arch = "x64"; + }; - "aarch64-linux" = { - os = "ubuntu-latest"; - arch = "aarch64"; - }; + "aarch64-linux" = { + os = "self-hosted"; + arch = "aarch64"; + }; - "x86_64-darwin" = { - os = "macos-latest"; - arch = "x64"; - }; - }; + "x86_64-darwin" = { + os = "macos-latest"; + arch = "x64"; + }; + } + ''; }; exclude = mkOption { @@ -108,7 +129,7 @@ in { default = []; example = literalExpression '' { - githubWorkflowGenerator.exclude = [ + nix2workflow.exclude = [ "packages.x86_64-linux.foo" ]; } @@ -121,7 +142,7 @@ in { default = {}; example = literalExpression '' { - githubWorkflowGenerator.overrides = { + nix2workflow.overrides = { checks.systems = [ "x86_64-linux" ]; }; } @@ -130,7 +151,7 @@ in { }; }; - config.flake.githubWorkflow = { - matrix.include = filter (job: !builtins.elem job.attr cfg.exclude) unfilteredJobs; + config.flake.workflowMatrix = { + include = filter (job: !elem job.attr cfg.exclude) jobs; }; } diff --git a/test/lib/flake.nix b/test/lib/flake.nix index c4607dc..985c421 100644 --- a/test/lib/flake.nix +++ b/test/lib/flake.nix @@ -19,8 +19,8 @@ "aarch64-darwin" ]; - forAllSystems = fn: lib.genAttrs systems (sys: fn nixpkgs.legacyPackages.${sys}); - workflow = (call-flake ../../.).lib {inherit self;}; + forSystem = system: fn: fn nixpkgs.legacyPackages.${system}; + forAllSystems = fn: lib.genAttrs systems (sys: forSystem sys fn); in { devShells = forAllSystems (pkgs: { default = pkgs.mkShell { @@ -28,21 +28,40 @@ }; }); + flatPackages = forSystem "x86_64-linux" ({hello, ...}: {inherit hello;}); + packages = forAllSystems (pkgs: { inherit (pkgs) hello; default = pkgs.hello; }); - githubWorkflow = let - outputs = ["packages" "devShells"]; - jobs = lib.concatLists ( - map ( - output: workflow.mkMatrix {inherit output;} - ) - outputs + workflowMatrix = let + platforms = { + x86_64-linux = { + os = "ubuntu-latest"; + arch = "x64"; + }; + + aarch64-linux = { + os = "ubuntu-latest"; + arch = "aarch64"; + }; + }; + + inherit ((call-flake ../../.).lib {inherit platforms;}) mkMatrix mkMatrix'; + + jobs = lib.flatten ( + (mkMatrix' { + root = self; + output = "flatPackages"; + }) + ++ (mkMatrix { + root = self; + output = "packages"; + }) ); in { - matrix.include = jobs; + include = jobs; }; }; } diff --git a/test/module/flake.nix b/test/module/flake.nix index 0bbbc54..c3d3e0e 100644 --- a/test/module/flake.nix +++ b/test/module/flake.nix @@ -25,9 +25,15 @@ "aarch64-darwin" ]; - githubWorkflowGenerator.exclude = [ - "packages.x86_64-linux.otherHello" - ]; + nix2workflow = { + exclude = [ + "packages.x86_64-linux.otherHello" + ]; + + overrides = { + devShells.systems = ["x86_64-linux"]; + }; + }; perSystem = {pkgs, ...}: { devShells.default = pkgs.mkShell { |
