diff --git a/cells/repo/ci.nix b/cells/repo/ci.nix index b0798f3..e3868a2 100644 --- a/cells/repo/ci.nix +++ b/cells/repo/ci.nix @@ -3,8 +3,19 @@ in cilib.mkCI { pipelines."default" = { - stages = ["build" "deploy"]; + stages = ["test" "build" "deploy"]; jobs = { + "test:lib" = { + stage = "test"; + script = [ + "nix run .#tests -- --junit=junit.xml" + ]; + allow_failure = true; + artifacts = { + when = "always"; + reports.junit = "junit.xml"; + }; + }; "docs" = { stage = "build"; script = [ diff --git a/cells/repo/docs.nix b/cells/repo/docs.nix index eda2205..4b52a41 100644 --- a/cells/repo/docs.nix +++ b/cells/repo/docs.nix @@ -36,6 +36,7 @@ in {"API Reference" = "api.md";} {"Related Libraries" = "libraries.md";} {"Direnv Integration" = "direnv.md";} + {"Debugging" = "debugging.md";} ]; markdown_extensions = [ { diff --git a/cells/repo/flake.lock b/cells/repo/flake.lock index b99a60f..fb920c3 100644 --- a/cells/repo/flake.lock +++ b/cells/repo/flake.lock @@ -3,11 +3,11 @@ "devshell": { "locked": { "dir": "lib", - "lastModified": 1758204313, - "narHash": "sha256-ainbY0Oajb1HMdvy+A8QxF/P5qwcbEzJGEY5pzKdDdc=", + "lastModified": 1767218348, + "narHash": "sha256-8MJqwH9sRMuHH+RsB7iqWyWD30TgmpiYKEvegAULggs=", "owner": "rensa-nix", "repo": "devshell", - "rev": "7d0c4bc78d9f017a739b0c7eb2f4e563118353e6", + "rev": "7a9b7e5d9f162a1fa3edfdc0169cdc29d3a67f8e", "type": "gitlab" }, "original": { @@ -20,11 +20,11 @@ "devtools-lib": { "locked": { "dir": "lib", - "lastModified": 1766237846, - "narHash": "sha256-7n3WFabnf49SFHXD/e4zfLit3BniZZOecUXfBm3d1d0=", + "lastModified": 1767214272, + "narHash": "sha256-gvW7flZ60xdv3Z3Ksec5jcRjW2sqRHsGoJdwsNWQVPk=", "owner": "rensa-nix", "repo": "devtools", - "rev": "5c8712f48c5bcb6b79d3da1afd1268f84f5e35e3", + "rev": "f40e59c32c48cdbf4cbc621c2f0f11e7bb80dbd3", "type": "gitlab" }, "original": { @@ -55,11 +55,11 @@ "nixmkdocs": { "locked": { "dir": "lib", - "lastModified": 1766062227, - "narHash": "sha256-jhr5CUi9eDeMIAJn7ayXP8Wr+Y2loV5EhdDIKDkRIdw=", + "lastModified": 1766404754, + "narHash": "sha256-EjBe6x6BT8ckPirMWhSf1GfaFxORYxR/Uu71FvSAm60=", "owner": "TECHNOFAB", "repo": "nixmkdocs", - "rev": "cb0bb5dc3382e8ba5d81324a2f1fd94ccd5a5df4", + "rev": "cfa9606eeeb9288e2799896d7d42b3d3860f9ccb", "type": "gitlab" }, "original": { @@ -69,12 +69,31 @@ "type": "gitlab" } }, + "nixtest-lib": { + "locked": { + "dir": "lib", + "lastModified": 1765728058, + "narHash": "sha256-V3FXECl1oTxEtGteNz3o3GJs/X8asSn1TxRpZ2F+htU=", + "owner": "TECHNOFAB", + "repo": "nixtest", + "rev": "2477ad31ae3aa4134e1bb5eeddbebe0cb64ccb57", + "type": "gitlab" + }, + "original": { + "dir": "lib", + "owner": "TECHNOFAB", + "ref": "v1.2.1", + "repo": "nixtest", + "type": "gitlab" + } + }, "root": { "inputs": { "devshell": "devshell", "devtools-lib": "devtools-lib", "nix-gitlab-ci-lib": "nix-gitlab-ci-lib", "nixmkdocs": "nixmkdocs", + "nixtest-lib": "nixtest-lib", "soonix-lib": "soonix-lib", "treefmt-nix": "treefmt-nix" } @@ -99,11 +118,11 @@ "treefmt-nix": { "flake": false, "locked": { - "lastModified": 1766000401, - "narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=", + "lastModified": 1767122417, + "narHash": "sha256-yOt/FTB7oSEKQH9EZMFMeuldK1HGpQs2eAzdS9hNS/o=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd", + "rev": "dec15f37015ac2e774c84d0952d57fcdf169b54d", "type": "github" }, "original": { diff --git a/cells/repo/flake.nix b/cells/repo/flake.nix index 46a3c1d..8180fcc 100644 --- a/cells/repo/flake.nix +++ b/cells/repo/flake.nix @@ -5,6 +5,7 @@ soonix-lib.url = "gitlab:TECHNOFAB/soonix?dir=lib"; nix-gitlab-ci-lib.url = "gitlab:TECHNOFAB/nix-gitlab-ci/3.1.2?dir=lib"; devtools-lib.url = "gitlab:rensa-nix/devtools?dir=lib"; + nixtest-lib.url = "gitlab:TECHNOFAB/nixtest/v1.2.1?dir=lib"; treefmt-nix = { url = "github:numtide/treefmt-nix"; flake = false; @@ -18,6 +19,8 @@ doclib = i.nixmkdocs.lib {inherit (i.parent) pkgs;}; soonix = i.soonix-lib.lib {inherit (i.parent) pkgs;}; cilib = i.nix-gitlab-ci-lib.lib {inherit (i.parent) pkgs;}; + ntlib = i.nixtest-lib.lib {inherit (i.parent) pkgs;}; + rensa = import "${i.parent.self}/lib" {inherit (i.parent.pkgs) lib;}; treefmt = import i.treefmt-nix; }; } diff --git a/cells/repo/tests.nix b/cells/repo/tests.nix new file mode 100644 index 0000000..fa75087 --- /dev/null +++ b/cells/repo/tests.nix @@ -0,0 +1,10 @@ +{inputs, ...}: let + inherit (inputs) pkgs ntlib rensa; +in { + tests = ntlib.mkNixtest { + modules = ntlib.autodiscover {dir = "${inputs.self}/tests";}; + args = { + inherit pkgs ntlib rensa; + }; + }; +} diff --git a/docs/api.md b/docs/api.md index 2500ca3..a4620f8 100644 --- a/docs/api.md +++ b/docs/api.md @@ -8,7 +8,7 @@ The main entry point for creating a Rensa flake. - `inputs`: The flake inputs. - `cellsFrom`: Path to the directory containing your cells. -- `cellBlocks`: A list of blocks to load for each cell. +- `cellBlocks`: A list of blocks to load for each cell. Defaults to `[rensa.blocks.autodiscover]`. - `transformInputs` (optional): A function to transform inputs before they are passed to cells. ### Returns @@ -23,7 +23,7 @@ The underlying builder function used by `buildWith`. It returns the raw Rensa ou - `inputs`: The flake inputs. - `cellsFrom`: Path to the directory containing your cells. -- `cellBlocks`: A list of blocks to load for each cell. +- `cellBlocks`: A list of blocks to load for each cell. Defaults to `[rensa.blocks.autodiscover]`. - `transformInputs` (optional): A function to transform inputs. ### Returns @@ -56,6 +56,45 @@ by passing through actions etc. from a cell. Currently not really used. +### `autodiscover` + +```nix +autodiscover +# or +(autodiscover "cellName") +``` + +Automatically discovers and loads all cell blocks by scanning the cells directory for `.nix` files. +When `autodiscover` is present in `cellBlocks`, Rensa will: + +1. Walk through all cells in `cellsFrom` (or specific cell if provided). +1. Find all `.nix` files (excluding `flake.nix`). +1. Find all directories containing `default.nix`. +1. Generate `simple` block definitions for each discovered block. + +**Usage patterns:** + +```nix +# full autodiscovery +cellBlocks = with rensa.blocks; [ + autodiscover +]; +# or +cellBlocks = with rensa.blocks; [ + (autodiscover "backend") # only discover blocks from backend cell + (autodiscover "frontend") # only discover blocks from frontend cell +]; +# mixed +cellBlocks = with rensa.blocks; [ + (simple "myBlock") # explicit block (takes precedence) + autodiscover # discover all others +]; +``` + +!!! note + + When a block is both explicitly defined and discovered, the explicit definition takes precedence. + ## `rensa.select` Helper to select specific outputs from the generated flake. diff --git a/docs/debugging.md b/docs/debugging.md new file mode 100644 index 0000000..2f0343b --- /dev/null +++ b/docs/debugging.md @@ -0,0 +1,38 @@ +# Debugging + +## Error Context + +To help with debugging, Rensa uses Nix's `builtins.addErrorContext` to add context +about where an error is happening. + +Use the following command to get just these logs from Rensa and please include that (or the whole stacktrace) in any issues or bug reports :) + +```sh +nix ... --show-trace 2> >(grep "… \[ren\]") +``` + +## Trace Verbose + +There are also some `traceVerbose` calls in Rensa, so to debug non-failing executions +just run Nix with the `--trace-verbose` flag. + +The output could look like this (example with this repo's flake): + +```sh +trace: [ren] loading cell block ci, type ci, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-darwin +trace: [ren] loading cell block devShells, type devShells, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-darwin +trace: [ren] loading cell block docs, type docs, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-darwin +trace: [ren] loading cell block soonix, type soonix, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-darwin +trace: [ren] loading cell block ci, type ci, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-linux +trace: [ren] loading cell block devShells, type devShells, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-linux +trace: [ren] loading cell block docs, type docs, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-linux +trace: [ren] loading cell block soonix, type soonix, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system aarch64-linux +trace: [ren] loading cell block ci, type ci, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-darwin +trace: [ren] loading cell block devShells, type devShells, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-darwin +trace: [ren] loading cell block docs, type docs, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-darwin +trace: [ren] loading cell block soonix, type soonix, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-darwin +trace: [ren] loading cell block ci, type ci, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-linux +trace: [ren] loading cell block devShells, type devShells, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-linux +trace: [ren] loading cell block docs, type docs, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-linux +trace: [ren] loading cell block soonix, type soonix, from cell /nix/store/7acz6q9360fkg0x187yx43d1vwpv850l-cells/repo, for system x86_64-linux +``` diff --git a/flake.lock b/flake.lock index 4baf8fb..8792074 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1766125104, - "narHash": "sha256-l/YGrEpLromL4viUo5GmFH3K5M1j0Mb9O+LiaeCPWEM=", + "lastModified": 1767151656, + "narHash": "sha256-ujL2AoYBnJBN262HD95yer7QYUmYp5kFZGYbyCCKxq8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7d853e518814cca2a657b72eeba67ae20ebf7059", + "rev": "f665af0cdb70ed27e1bd8f9fdfecaf451260fc55", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1765674936, - "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "lastModified": 1766884708, + "narHash": "sha256-x8nyRwtD0HMeYtX60xuIuZJbwwoI7/UKAdCiATnQNz0=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "rev": "15177f81ad356040b4460a676838154cbf7f6213", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a47fa5a..52b2326 100644 --- a/flake.nix +++ b/flake.nix @@ -24,12 +24,14 @@ (simple "docs") (simple "ci") (simple "soonix") + (simple "tests") ]; } { packages = rensa.select inputs.self [ ["repo" "docs"] ["repo" "ci" "packages"] ["repo" "soonix" "packages"] + ["repo" "tests"] ]; }; } diff --git a/lib/blocks/default.nix b/lib/blocks/default.nix index 7f83c8d..ebaea9a 100644 --- a/lib/blocks/default.nix +++ b/lib/blocks/default.nix @@ -6,6 +6,17 @@ dynamic = name: { inherit name; type = name; + cli = true; + actions = args: {}; # TODO: dynamic actions }; + autodiscover = { + name = "__autodiscover"; + type = "__autodiscover"; + _functor = self: cell: + self + // { + inherit cell; + }; + }; } diff --git a/lib/core/autodiscover.nix b/lib/core/autodiscover.nix new file mode 100644 index 0000000..9bec7c2 --- /dev/null +++ b/lib/core/autodiscover.nix @@ -0,0 +1,98 @@ +{ + l, + cellsFrom, + cellBlocks, +}: let + # find autodiscover blocks + autodiscoverBlocks = l.filter (block: block.name or "" == "__autodiscover") cellBlocks; + explicitBlocks = l.filter (block: block.name or "" != "__autodiscover") cellBlocks; + hasAutodiscover = (l.length autodiscoverBlocks) > 0; + + # discover all block names from a single cell's directory + discoverBlocksFromCell = cellPath: let + cellContents = l.readDir cellPath; + # filter for .nix files (but not flake.nix) and dirs with default.nix + blockNames = l.unique ( + l.filter (name: name != null) ( + l.mapAttrsToList ( + name: type: + if type == "regular" && l.hasSuffix ".nix" name && name != "flake.nix" + then l.removeSuffix ".nix" name + else if type == "directory" && l.pathExists (cellPath + "/${name}/default.nix") + then name + else null + ) + cellContents + ) + ); + in + builtins.addErrorContext "[ren] while discovering blocks from cell ${cellPath}" + blockNames; + + # discover all blocks from all cells or specific cells + discoverAllBlocks = let + # check if any autodiscover blocks have cell-specific targets (eg. `autodiscover "a"`) + cellSpecificDiscoveries = l.filter (block: block ? cell) autodiscoverBlocks; + globalDiscoveries = l.filter (block: !(block ? cell)) autodiscoverBlocks; + + cellSpecificBlocks = l.flatten ( + l.map ( + block: let + cellPath = cellsFrom + "/${block.cell}"; + in + if l.pathExists cellPath + then discoverBlocksFromCell cellPath + else [] + ) + cellSpecificDiscoveries + ); + + # global autodiscover + globalBlocks = builtins.addErrorContext "[ren] while discovering global blocks" ( + if (l.length globalDiscoveries) > 0 + then let + cells = l.readDir cellsFrom; + allBlockNames = l.unique ( + l.flatten ( + l.mapAttrsToList ( + cellName: cellType: + if cellType == "directory" + then discoverBlocksFromCell (cellsFrom + "/${cellName}") + else [] + ) + cells + ) + ); + in + allBlockNames + else [] + ); + + allBlockNames = l.unique (cellSpecificBlocks ++ globalBlocks); + in + builtins.addErrorContext "[ren] while discovering all blocks" + l.map (name: { + inherit name; + type = name; + }) + allBlockNames; + + discoveredBlocks = + if hasAutodiscover + then discoverAllBlocks + else []; + + # merge the explicit and autodiscovered blocks (explicit taking precedence) + allBlocks = explicitBlocks ++ discoveredBlocks; + uniqueBlocks = + l.foldl' ( + acc: block: + # first occurence of name wins + if l.any (b: b.name == block.name) acc + then acc + else acc ++ [block] + ) [] + allBlocks; +in + builtins.addErrorContext "[ren] while autodiscovering cell blocks" + uniqueBlocks diff --git a/lib/core/builder.nix b/lib/core/builder.nix index 86c2a65..7a8307b 100644 --- a/lib/core/builder.nix +++ b/lib/core/builder.nix @@ -2,6 +2,8 @@ l, utils, loader, + autodiscover, + blocks, }: let inherit (utils) accumulate; inherit (loader) createCellLoader; @@ -9,7 +11,7 @@ build = { inputs, cellsFrom, - cellBlocks, + cellBlocks ? [blocks.autodiscover], transformInputs ? system: i: i, ... } @ args: let @@ -28,26 +30,31 @@ ] ); + cellBlocks' = autodiscover {inherit l cellsFrom cellBlocks;}; + cells = res.output; loadOutputFor = system: let loadCell = createCellLoader { - inherit inputs system cells cellsFrom cellBlocks transformInputs; + inherit inputs system cells cellsFrom transformInputs; + cellBlocks = cellBlocks'; }; cells' = l.mapAttrsToList (cell: type: cell) (l.readDir cellsFrom); res = accumulate (l.map loadCell cells'); - in [ - {${system} = res.output;} - {${system} = res.actions;} - { - name = system; - value = res.init; - } - ]; + in + builtins.addErrorContext "[ren] while loading output for ${system}" [ + {${system} = res.output;} + {${system} = res.actions;} + { + name = system; + value = res.init; + } + ]; res = accumulate (l.map loadOutputFor systems); in + builtins.addErrorContext "[ren] while building rensa output" res.output // { __ren = { @@ -89,10 +96,12 @@ recursiveUpdate = lhs: rhs: recursiveUpdateUntil g lhs rhs; in - build args - // { - __functor = l.flip recursiveUpdate; - }; + builtins.addErrorContext "[ren] while building rensa output (buildWith)" ( + build args + // { + __functor = l.flip recursiveUpdate; + } + ); in { inherit build buildWith; } diff --git a/lib/core/call-flake.nix b/lib/core/call-flake.nix index 6bd325a..5961981 100644 --- a/lib/core/call-flake.nix +++ b/lib/core/call-flake.nix @@ -112,4 +112,5 @@ ref: inputOverrides: let ) lockFile.nodes; in + builtins.addErrorContext "[ren] while loading flake lockfile ${ref}" allNodes.${lockFile.root} diff --git a/lib/core/default.nix b/lib/core/default.nix index 25a3f44..3276941 100644 --- a/lib/core/default.nix +++ b/lib/core/default.nix @@ -1,11 +1,13 @@ { l, utils, + blocks, }: let paths = import ./paths.nix; callFlake = import ./call-flake.nix; + autodiscover = import ./autodiscover.nix; loader = import ./loader.nix {inherit l utils paths callFlake;}; - builder = import ./builder.nix {inherit l utils loader;}; + builder = import ./builder.nix {inherit l utils loader autodiscover blocks;}; in { inherit (builder) build buildWith; } diff --git a/lib/core/loader.nix b/lib/core/loader.nix index eec8e70..1c6a0fc 100644 --- a/lib/core/loader.nix +++ b/lib/core/loader.nix @@ -33,14 +33,18 @@ }).outputs else {}; in - importSignatureFor system updatedCell cells additionalInputs; + builtins.addErrorContext "[ren] while getting input signature for ${blockP}" ( + importSignatureFor system updatedCell cells additionalInputs + ); import' = importPath: let block = import importPath; in if l.typeOf block == "set" then block - else block signature; + else + builtins.addErrorContext "[ren] while importing block at ${importPath}" + (block signature); importPaths = if isFile @@ -101,18 +105,20 @@ in optionalLoad (isFile || isDir) ( assert l.assertMsg isAttrs "cell block does not return an attrset: ${importPaths.displayPath}"; - l.traceVerbose "[ren] loading cell block ${cellBlock.name}, type ${cellBlock.type}, from cell ${cellP}" - [ - {${cellBlock.name} = imported;} - {${cellBlock.name} = l.mapAttrs (_: set: set.actions) extracted;} - ({ - cellBlock = cellBlock.name; - blockType = cellBlock.type; - targets = l.mapAttrsToList (_: set: set.init) extracted; - } - // (l.optionalAttrs (l.pathExists blockP.readmeDir) {readme = blockP.readmeDir;}) - // (l.optionalAttrs (l.pathExists blockP.readme) {inherit (blockP) readme;})) - ] + l.traceVerbose "[ren] loading cell block ${cellBlock.name}, type ${cellBlock.type}, from cell ${cellP}, for system ${system}" ( + builtins.addErrorContext "[ren] loading cell block ${cellBlock.name}, type ${cellBlock.type}, from cell ${cellP}, for system ${system}" + [ + {${cellBlock.name} = imported;} + {${cellBlock.name} = l.mapAttrs (_: set: set.actions) extracted;} + ({ + cellBlock = cellBlock.name; + blockType = cellBlock.type; + targets = l.mapAttrsToList (_: set: set.init) extracted; + } + // (l.optionalAttrs (l.pathExists blockP.readmeDir) {readme = blockP.readmeDir;}) + // (l.optionalAttrs (l.pathExists blockP.readme) {inherit (blockP) readme;})) + ] + ) ); in loadCellBlock; @@ -133,7 +139,7 @@ # fixes `ìnfinite recursion` errors when accessing cell attributes from sibling blocks # example: cells/test/a.nix returns `cell.b`, so the same thing as cells/test/b.nix. # this would previously fail with infinite recursion, this makes it work: - cell = l.listToAttrs (l.concatMap ( + cell = builtins.addErrorContext "[ren] while accessing cell '${cellName}' siblings" (l.listToAttrs (l.concatMap ( block: let blockP = paths.cellBlockPath cellP block; exists = l.pathExists blockP.file || l.pathExists blockP.dir; @@ -148,18 +154,19 @@ ] else [] ) - cellBlocks'); + cellBlocks')); loadCellBlock = createCellBlockLoader {inherit inputs system cells cell transformInputs;}; res = accumulate (l.map (loadCellBlock cellName cellP) cellBlocks'); - in [ - {${cellName} = res.output;} - {${cellName} = res.actions;} - ({ - cell = cellName; - cellBlocks = res.init; - } - // (l.optionalAttrs (l.pathExists cellP.readme) {inherit (cellP) readme;})) - ]; + in + builtins.addErrorContext "[ren] while loading cell ${cellName}" [ + {${cellName} = res.output;} + {${cellName} = res.actions;} + ({ + cell = cellName; + cellBlocks = res.init; + } + // (l.optionalAttrs (l.pathExists cellP.readme) {inherit (cellP) readme;})) + ]; in loadCell; in { diff --git a/lib/default.nix b/lib/default.nix index d76620f..498d8d1 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,9 +1,9 @@ {lib}: let l = builtins // lib; - utils = import ./utils {inherit l;}; - core = import ./core {inherit l utils;}; - compat = import ./compat {inherit l;}; blocks = import ./blocks; + utils = import ./utils {inherit l;}; + compat = import ./compat {inherit l;}; + core = import ./core {inherit l utils blocks;}; in { inherit (compat) filter select get; inherit (core) build buildWith; diff --git a/lib/flake.lock b/lib/flake.lock index f7915ba..293dc4e 100644 --- a/lib/flake.lock +++ b/lib/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs-lib": { "locked": { - "lastModified": 1754184128, - "narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", + "lastModified": 1766884708, + "narHash": "sha256-x8nyRwtD0HMeYtX60xuIuZJbwwoI7/UKAdCiATnQNz0=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "02e72200e6d56494f4a7c0da8118760736e41b60", + "rev": "15177f81ad356040b4460a676838154cbf7f6213", "type": "github" }, "original": { diff --git a/tests/autodiscovery_test.nix b/tests/autodiscovery_test.nix new file mode 100644 index 0000000..51c9205 --- /dev/null +++ b/tests/autodiscovery_test.nix @@ -0,0 +1,63 @@ +{ + pkgs, + ntlib, + ... +}: { + suites."Autodiscovery" = { + pos = __curPos; + tests = [ + { + name = "find nix files"; + type = "script"; + script = '' + ${ntlib.helpers.path [pkgs.gnugrep pkgs.coreutils pkgs.nix]} + ${ntlib.helpers.scriptHelpers} + + mkdir -p "testcell" + echo '{ foo = "bar"; }' > "testcell/packages.nix" + echo '{ baz = "qux"; }' > "testcell/devShells.nix" + echo '{ ignored = true; }' > "testcell/flake.nix" + + result=$(nix eval --impure --expr ' + let + lib = import ${pkgs.path}/lib; + autodiscover = import ${../lib/core/autodiscover.nix} { + l = builtins // lib; + cellsFrom = ./.; + cellBlocks = [ { name = "__autodiscover"; } ]; + }; + in + builtins.length (builtins.filter (b: b.name == "packages" || b.name == "devShells") autodiscover) + ') + + assert_eq "$result" "2" "should discover 2 blocks" + ''; + } + { + name = "finds directories"; + type = "script"; + script = '' + ${ntlib.helpers.path [pkgs.gnugrep pkgs.coreutils pkgs.nix]} + ${ntlib.helpers.scriptHelpers} + + mkdir -p "testcell/packages" + echo '{ hello = "world"; }' > "testcell/packages/default.nix" + + result=$(nix eval --impure --expr ' + let + lib = import ${pkgs.path}/lib; + autodiscover = import ${../lib/core/autodiscover.nix} { + l = builtins // lib; + cellsFrom = ./.; + cellBlocks = [ { name = "__autodiscover"; } ]; + }; + in + builtins.any (b: b.name == "packages") autodiscover + ') + + assert "$result == true" "Should discover directory with default.nix" + ''; + } + ]; + }; +} diff --git a/tests/builder_test.nix b/tests/builder_test.nix new file mode 100644 index 0000000..a520b43 --- /dev/null +++ b/tests/builder_test.nix @@ -0,0 +1,90 @@ +{ + pkgs, + ntlib, + rensa, + ... +}: { + suites."Builder" = { + pos = __curPos; + tests = [ + { + name = "has system outputs"; + expected = true; + actual = let + testFlake = rensa.build { + inputs = {}; + cellsFrom = ../cells; + cellBlocks = with rensa.blocks; [ + (simple "test") + ]; + systems = ["x86_64-linux"]; + }; + in + builtins.hasAttr "x86_64-linux" testFlake; + } + { + name = "has ren metadata"; + expected = true; + actual = let + testFlake = rensa.build { + inputs = {}; + cellsFrom = ../cells; + cellBlocks = with rensa.blocks; [ + (simple "test") + ]; + systems = ["x86_64-linux"]; + }; + in + builtins.hasAttr "__ren" testFlake; + } + { + name = "merges outputs"; + expected = { + packages = { + test-package = "merged"; + }; + }; + actual = let + testFlake = + rensa.buildWith { + inputs = {}; + cellsFrom = ../cells; + cellBlocks = with rensa.blocks; [ + (simple "test") + ]; + systems = ["x86_64-linux"]; + } { + packages = { + test-package = "merged"; + }; + }; + in { + packages = testFlake.packages; + }; + } + { + name = "eval test"; + type = "script"; + script = '' + ${ntlib.helpers.path [pkgs.gnugrep pkgs.coreutils pkgs.nix]} + ${ntlib.helpers.scriptHelpers} + + result=$(nix eval --impure --expr ' + let + rensa = import ${../lib} {lib = import ${pkgs.path}/lib;}; + testFlake = rensa.build { + inputs = { test = "value"; }; + cellsFrom = ${../cells}; + cellBlocks = []; + systems = [ "x86_64-linux" ]; + }; + in + testFlake.__ren.__schema + ') + + assert "$result == \"v0\"" "should contain version" + ''; + } + ]; + }; +} diff --git a/tests/filter_test.nix b/tests/filter_test.nix new file mode 100644 index 0000000..f45f1a3 --- /dev/null +++ b/tests/filter_test.nix @@ -0,0 +1,51 @@ +{rensa, ...}: { + suites."Filter" = { + pos = __curPos; + tests = [ + { + name = "filter by cell"; + expected = { + x86_64-linux = {}; + }; + actual = let + testFlake = { + __ren = { + cells = ["repo" "other"]; + }; + x86_64-linux = { + repo = { + docs = {value = "docs-value";}; + ci = {value = "ci-value";}; + }; + other = { + packages = {value = "other-packages";}; + }; + }; + }; + in + rensa.filter (_: cell: cell == "repo") testFlake [["*" "*"]]; + } + { + name = "filter by block"; + expected = { + x86_64-linux = {}; + }; + actual = let + testFlake = { + __ren = { + cells = ["repo"]; + }; + x86_64-linux = { + repo = { + docs = {value = "docs-value";}; + ci = {value = "ci-value";}; + packages = {value = "packages-value";}; + }; + }; + }; + in + rensa.filter (block: _: block == "docs") testFlake [["repo" "*"]]; + } + ]; + }; +} diff --git a/tests/loader_test.nix b/tests/loader_test.nix new file mode 100644 index 0000000..9732293 --- /dev/null +++ b/tests/loader_test.nix @@ -0,0 +1,57 @@ +{ + pkgs, + ntlib, + rensa, + ... +}: { + suites."Loader" = { + pos = __curPos; + tests = [ + { + name = "cell sibling access"; + expected = { + hello = "world"; + }; + actual = let + testFlake = rensa.build { + inputs = {}; + cellsFrom = ../cells; + cellBlocks = with rensa.blocks; [ + (simple "test") + ]; + systems = ["x86_64-linux"]; + }; + in + testFlake.x86_64-linux.test.test; + } + { + name = "load file"; + type = "script"; + script = '' + ${ntlib.helpers.path [pkgs.gnugrep pkgs.coreutils pkgs.nix]} + ${ntlib.helpers.scriptHelpers} + + mkdir -p "cells/testcell" + echo '{ hello = "world"; }' > "cells/testcell/packages.nix" + + cat > "flake.nix" << 'EOF' + { + outputs = inputs: let + rensa = import ${../lib} { lib = import "${pkgs.path}/lib"; }; + in rensa.build { + inputs = {}; + cellsFrom = ./cells; + cellBlocks = with rensa.blocks; [ (simple "packages") ]; + systems = [ "x86_64-linux" ]; + }; + } + EOF + + result=$(nix eval --impure .#x86_64-linux.testcell.packages.hello) + + assert "$result == \"world\"" "should equal to world" + ''; + } + ]; + }; +} diff --git a/tests/select_test.nix b/tests/select_test.nix new file mode 100644 index 0000000..823e101 --- /dev/null +++ b/tests/select_test.nix @@ -0,0 +1,49 @@ +{rensa, ...}: { + suites."Select" = { + pos = __curPos; + tests = [ + { + name = "single block"; + expected = { + x86_64-linux = {value = "test-value";}; + }; + actual = let + testFlake = { + __ren = { + cells = ["repo"]; + }; + x86_64-linux = { + repo = { + docs = {value = "test-value";}; + ci = {packages = {value = "ci-packages";};}; + }; + }; + }; + in + rensa.select testFlake [["repo" "docs"]]; + } + { + name = "multiple blocks"; + expected = { + x86_64-linux = {value = "ci-packages";}; + }; + actual = let + testFlake = { + __ren = { + cells = ["repo"]; + }; + x86_64-linux = { + repo = { + ci = {packages = {value = "ci-packages";};}; + other = {value = "ignored";}; + }; + }; + }; + in + rensa.select testFlake [ + ["repo" "ci" "packages"] + ]; + } + ]; + }; +}