tests: add `shellcheckServices`

This commit is contained in:
Erik Arvstedt 2022-09-05 18:12:09 +02:00 committed by Otto Sabart
parent 01fa900633
commit c3b97e6728
No known key found for this signature in database
GPG Key ID: 823BAE99F8BE1E3C
4 changed files with 139 additions and 1 deletions

View File

@ -9,8 +9,9 @@ name: testConfig:
vm = makeVM {
name = "nix-bitcoin-${name}";
nodes.machine = {
nodes.machine = { config, ... }: {
imports = [ testConfig ];
virtualisation = {
# Needed because duplicity requires 270 MB of free temp space, regardless of backup size
diskSize = 1024;
@ -20,6 +21,9 @@ name: testConfig:
cores = lib.mkDefault 2;
};
# Run shellcheck on all nix-bitcoin services during machine build time
system.extraDependencies = [ config.test.shellcheckServices ];
};
testScript = nodes: let

View File

@ -0,0 +1,128 @@
{ config, pkgs, lib, extendModules, ... }:
with lib;
let
options = {
test.shellcheckServices = mkOption {
readOnly = true;
description = ''
A derivation that runs shellcheck on all bash scripts included
in nix-bitcoin services.
'';
default = shellcheckServices;
};
};
# TODO-EXTERNAL:
# This can be removed when https://github.com/NixOS/nixpkgs/pull/189836 is merged.
#
# A list of all systemd service definitions and their locations, with format
# [
# {
# file = ...;
# value = { postgresql = ...; };
# }
# ...
# ]
systemdServiceDefs =
(extendModules {
modules = [
{
# Currently, NixOS modules only allow accessing option definition locations
# via type.merge.
# Override option `systemd.services` and use it to return the list of service defs.
options.systemd.services = lib.mkOption {
type = lib.types.anything // {
merge = loc: defs: defs;
};
};
# Disable all modules that define options.systemd.services so that these
# defs don't collide with our definition
disabledModules = [
"system/boot/systemd.nix"
# These files amend option systemd.services
"testing/service-runner.nix"
"security/systemd-confinement.nix"
];
config._module.check = false;
}
];
}).config.systemd.services;
# A list of all service names that are defined by nix-bitcoin.
# [ "bitcoind", "clightning", ... ]
#
# Algorithm: Parse `systemdServiceDefs` and return all services that
# only have definitions located in the nix-bitcoin source.
nix-bitcoin-services = let
nix-bitcoin-source = toString ../..;
nbServices = collectServices true;
nonNbServices = collectServices false;
# Return set of services ({ service1 = true; service2 = true; ... })
# which are either defined or not defined by nix-bitcoin, depending
# on `fromNixBitcoin`.
collectServices = fromNixBitcoin: lib.listToAttrs (builtins.concatLists (map (def:
let
isNbSource = lib.hasPrefix nix-bitcoin-source def.file;
in
# Nix has nor boolean XOR, so use `if`
lib.optionals (if fromNixBitcoin then isNbSource else !isNbSource) (
(map (service: { name = service; value = true; }) (builtins.attrNames def.value))
)
) systemdServiceDefs));
in
# Set difference: nbServices - nonNbServices
builtins.filter (nbService: ! nonNbServices ? ${nbService}) (builtins.attrNames nbServices);
# The concatenated list of values of ExecStart, ExecStop, ... (`scriptAttrs`) of all `nix-bitcoin-services`.
serviceCmds = let
scriptAttrs = [
"ExecStartPre"
"ExecStart"
"ExecStartPost"
"ExecStop"
"ExecStopPost"
"ExecCondition"
"ExecReload"
];
services = config.systemd.services;
in
builtins.concatMap (serviceName: let
serviceCfg = services.${serviceName}.serviceConfig;
in
builtins.concatMap (attr:
lib.optionals (serviceCfg ? ${attr}) (
let
cmd = serviceCfg.${attr};
in
if builtins.typeOf cmd == "list" then cmd else [ cmd ]
)
) scriptAttrs
) nix-bitcoin-services;
# A list of all binaries included in `serviceCmds`
serviceBinaries = map (cmd: builtins.head (
# Extract the first component (the binary).
# cmd can start with extra modifiers like `+`
builtins.match "[^/]*([^[:space:]]+).*" (toString cmd)
)) serviceCmds;
shellcheckServices = pkgs.runCommand "shellcheck-services" {
inherit serviceBinaries;
# The `builtins.match` in `serviceBinaries` discards the string context, so we
# also have to add `serviceCmds` to the derivation. This ensures that all
# referenced nix paths are available to the builder.
inherit serviceCmds;
} ''
echo "Checked binaries:"
# Find and check all binaries that have a bash shebang
grep -Pl '\A#! *\S+bash\b' $serviceBinaries | while IFS= read -r script; do
echo "$script"
${pkgs.shellcheck}/bin/shellcheck --shell bash "$script"
done | tee "$out"
'';
in
{
inherit options;
}

View File

@ -1,6 +1,10 @@
{ config, lib, ... }:
with lib;
{
imports = [
./shellcheck-services.nix
];
options = {
test = {
noConnections = mkOption {

View File

@ -2,6 +2,8 @@
set -euo pipefail
. "${BASH_SOURCE[0]%/*}/../helper/run-in-nix-env" "shellcheck findutils gnugrep" "$@"
# Shellcheck all bash sources in this repo
cd "${BASH_SOURCE[0]%/*}/.."
{
# Skip .git dir in all find commands