checks.nix (3774B)
1 { 2 crane, 3 lib, 4 pkgs, 5 }: 6 { 7 serviceName, 8 toolchain, 9 source, 10 cargoLock, 11 nativeInputs, 12 package, 13 hooks, 14 extraChecks ? { }, 15 }: 16 assert lib.assertMsg ( 17 builtins.isString serviceName && builtins.match "^[a-z][a-z0-9_]*$" serviceName != null 18 ) "serviceName must be a lowercase snake-case identifier"; 19 assert lib.assertMsg (lib.isDerivation toolchain) "toolchain must be a derivation"; 20 assert lib.assertMsg (builtins.pathExists source) "source must exist"; 21 assert lib.assertMsg (builtins.pathExists cargoLock) "cargoLock must exist"; 22 assert lib.assertMsg ( 23 builtins.isAttrs nativeInputs 24 && (nativeInputs.schema or null) == "radroots.service.native-inputs.v1" 25 && builtins.isList (nativeInputs.nativeBuildInputs or null) 26 && builtins.isList (nativeInputs.buildInputs or null) 27 && builtins.isAttrs (nativeInputs.environment or null) 28 ) "nativeInputs must come from mkNativeInputs"; 29 assert lib.assertMsg (lib.all (name: !(builtins.hasAttr name nativeInputs.environment)) [ 30 "CARGO_PROFILE" 31 "RUSTDOCFLAGS" 32 "RUSTFLAGS" 33 ]) "nativeInputs.environment must not weaken the standard check policy"; 34 assert lib.assertMsg (lib.isDerivation package) "package must be a derivation"; 35 assert lib.assertMsg (builtins.isAttrs hooks) "hooks must be an attribute set"; 36 assert lib.assertMsg ( 37 builtins.attrNames hooks == [ 38 "config" 39 "integration" 40 "source-lock" 41 "sqlx" 42 ] 43 ) "hooks must provide exactly config, integration, source-lock, and sqlx"; 44 assert lib.assertMsg (lib.all (name: lib.isDerivation hooks.${name}) ( 45 builtins.attrNames hooks 46 )) "every service-specific hook must be a derivation"; 47 assert lib.assertMsg (builtins.isAttrs extraChecks) "extraChecks must be an attribute set"; 48 assert lib.assertMsg (lib.all 49 (name: builtins.match "^[a-z][a-z0-9-]*$" name != null && lib.isDerivation extraChecks.${name}) 50 (builtins.attrNames extraChecks) 51 ) "extraChecks must contain lowercase check names bound to derivations"; 52 let 53 standardNames = [ 54 "check" 55 "clippy" 56 "config" 57 "docs" 58 "fmt" 59 "integration" 60 "package" 61 "source-lock" 62 "sqlx" 63 "test" 64 ]; 65 in 66 assert lib.assertMsg ( 67 builtins.length ( 68 builtins.attrNames (builtins.intersectAttrs extraChecks (lib.genAttrs standardNames (_: null))) 69 ) == 0 70 ) "extraChecks must not replace a standard check"; 71 let 72 craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; 73 commonArgs = { 74 pname = "${serviceName}-checks"; 75 version = "1"; 76 src = craneLib.cleanCargoSource source; 77 inherit cargoLock; 78 strictDeps = true; 79 nativeBuildInputs = nativeInputs.nativeBuildInputs; 80 buildInputs = nativeInputs.buildInputs; 81 env = nativeInputs.environment; 82 doCheck = false; 83 }; 84 cargoArtifacts = craneLib.buildDepsOnly commonArgs; 85 mkCargoCheck = 86 name: command: extraArgs: 87 craneLib.mkCargoDerivation ( 88 commonArgs 89 // extraArgs 90 // { 91 inherit cargoArtifacts; 92 pname = "${serviceName}-${name}"; 93 buildPhaseCargoCommand = command; 94 installPhaseCommand = "mkdir -p $out"; 95 } 96 ); 97 standardChecks = { 98 fmt = craneLib.cargoFmt ( 99 commonArgs 100 // { 101 pname = "${serviceName}-fmt"; 102 } 103 ); 104 check = mkCargoCheck "check" "cargo check --workspace --all-targets --locked" { }; 105 test = mkCargoCheck "test" "cargo test --workspace --all-targets --locked" { }; 106 clippy = mkCargoCheck "clippy" "cargo clippy --workspace --all-targets --locked -- -D warnings" { }; 107 docs = mkCargoCheck "docs" "cargo doc --workspace --no-deps --locked" { 108 RUSTDOCFLAGS = "-D warnings"; 109 }; 110 sqlx = hooks.sqlx; 111 config = hooks.config; 112 source-lock = hooks."source-lock"; 113 package = package; 114 integration = hooks.integration; 115 }; 116 in 117 standardChecks // extraChecks