Skip to content

Commit

Permalink
flake: Move clang-tidy jobs into checks
Browse files Browse the repository at this point in the history
The checks Flake attribute contains derivations that are built whenever
we perform a "nix flake check" and given that Clang-Tidy linting our
code is only really useful if we make sure that we never push code that
has Clang-Tidy failures.

To enforce this, let's move the clang-tidy Hydra job into the checks
attribute, that way we can easily run it prior to pushing and keep our
repository free from linting errors.

Of course, I also made sure that the clang-tidy job is built on Hydra as
well, by reintroducing the attribute under the "basic" job namespace.

Signed-off-by: aszlig <[email protected]>
  • Loading branch information
aszlig committed Aug 6, 2023
1 parent e3aecaf commit 53a8451
Showing 1 changed file with 174 additions and 161 deletions.
335 changes: 174 additions & 161 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,135 @@

withPkgs = f: forAllSystems (sys: f sys nixpkgs.legacyPackages.${sys});
forAllSystems = lib.genAttrs systems;

# This is with all the *required* dependencies only.
withSystem = fun: system: let
pkgs = nixpkgs.legacyPackages.${system};
attrs = fun pkgs;
stdenv = attrs.stdenv or pkgs.stdenv;

libyamlcpp =
if stdenv.cc.isClang then pkgs.libyamlcpp
else pkgs.libyamlcpp.override { inherit stdenv; };

in stdenv.mkDerivation (removeAttrs attrs [ "stdenv" ] // rec {
inherit (self.packages.${system}.ip2unix) name version src;

mesonFlags = [ "-Dtest-timeout=3600" ] ++ attrs.mesonFlags or [];

nativeBuildInputs = [ pkgs.meson pkgs.ninja pkgs.pkgconfig ]
++ attrs.nativeBuildInputs or [];
buildInputs = [ libyamlcpp ] ++ attrs.buildInputs or [];

doCheck = attrs.doCheck or true;

doInstallCheck = attrs.doInstallCheck or true;
installCheckPhase = attrs.installCheckPhase or ''
found=0
for man in "$out/share/man/man1"/ip2unix.1*; do
test -s "$man" && found=1
done
expected=${if attrs.requireManpage or true then "1" else "0"}
if [ $found -ne $expected ]; then
echo "ASSERTION: Manpage found($found) != expected($expected)" >&2
exit 1
fi
'';
});

# Bare minimum dependencies plus pytest for integration tests.
withSystemAndTests = fun: system: let
funWithTests = pkgs: let
funAttrs = fun pkgs;
in funAttrs // {
nativeBuildInputs = [
pkgs.python3Packages.pytest pkgs.python3Packages.pytest-timeout
] ++ funAttrs.nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program pytest found: YES' meson-logs/meson-log.txt
${funAttrs.postConfigure or ""}
'';
};
in withSystem funWithTests system;

# All the dependencies including optional ones.
withSystemFull = fun: system: let
funFull = pkgs: let
funAttrs = fun pkgs;
in funAttrs // {
nativeBuildInputs = [
pkgs.asciidoc pkgs.libxslt.bin pkgs.docbook_xml_dtd_45
pkgs.docbook_xsl pkgs.libxml2.bin pkgs.docbook5 pkgs.systemd
] ++ funAttrs.nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program systemd-socket-activate found: YES' \
meson-logs/meson-log.txt
${funAttrs.postConfigure or ""}
'';
};
in withSystemAndTests funFull system;

forEachSystem = f: lib.genAttrs hydraSystems (withSystem f);
testForEachSystem = f: lib.genAttrs hydraSystems (withSystemAndTests f);
fullForEachSystem = f: lib.genAttrs hydraSystems (withSystemFull f);

# Create Hydra jobs that generate manpages with either asciidoc or
# asciidoctor and perform validation so that we can make sure that builds
# without Nix get manpages irrespective on which AsciiDoc implementation
# they have installed.
mkManpageJobs = attrsFun: {
no-manpage = testForEachSystem (pkgs: (attrsFun pkgs) // {
requireManpage = false;
});

asciidoc = {
with-validation = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [
pkgs.libxslt.bin pkgs.docbook_xml_dtd_45 pkgs.docbook_xsl
pkgs.libxml2.bin pkgs.docbook5

# We want to pass the -v argument to a2x so that if we get a
# validation error it's actually shown in the build log. The
# reason we don't do this by default is because it would cause
# unnecessary build output when built on other systems.
(pkgs.runCommand "a2x-wrapped" {
nativeBuildInputs = [ pkgs.makeWrapper ];
a2x = "${pkgs.asciidoc}/bin/a2x";
} ''
mkdir -p "$out/bin"
makeWrapper "$a2x" "$out/bin/a2x" --add-flags -v
ln -s ${lib.escapeShellArg pkgs.asciidoc}/bin/asciidoc \
"$out/bin"
'')
] ++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program xmllint found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});

without-validation = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [
pkgs.asciidoc pkgs.libxslt.bin pkgs.docbook_xml_dtd_45
pkgs.docbook_xsl
] ++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program a2x found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});
};

asciidoctor = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [ pkgs.asciidoctor ]
++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program asciidoctor found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});
};

in {
packages = withPkgs (system: pkgs: {
default = self.packages.${system}.ip2unix;
Expand Down Expand Up @@ -80,133 +209,26 @@
};
});

hydraJobs = let
# This is with all the *required* dependencies only.
withSystem = fun: system: let
pkgs = nixpkgs.legacyPackages.${system};
attrs = fun pkgs;
stdenv = attrs.stdenv or pkgs.stdenv;

libyamlcpp =
if stdenv.cc.isClang then pkgs.libyamlcpp
else pkgs.libyamlcpp.override { inherit stdenv; };

in stdenv.mkDerivation (removeAttrs attrs [ "stdenv" ] // rec {
inherit (self.packages.${system}.ip2unix) name version src;

mesonFlags = [ "-Dtest-timeout=3600" ] ++ attrs.mesonFlags or [];

nativeBuildInputs = [ pkgs.meson pkgs.ninja pkgs.pkgconfig ]
++ attrs.nativeBuildInputs or [];
buildInputs = [ libyamlcpp ] ++ attrs.buildInputs or [];

doCheck = attrs.doCheck or true;

doInstallCheck = attrs.doInstallCheck or true;
installCheckPhase = attrs.installCheckPhase or ''
found=0
for man in "$out/share/man/man1"/ip2unix.1*; do
test -s "$man" && found=1
done
expected=${if attrs.requireManpage or true then "1" else "0"}
if [ $found -ne $expected ]; then
echo "ASSERTION: Manpage found($found) != expected($expected)" >&2
exit 1
fi
'';
});

# Bare minimum dependencies plus pytest for integration tests.
withSystemAndTests = fun: system: let
funWithTests = pkgs: let
funAttrs = fun pkgs;
in funAttrs // {
nativeBuildInputs = [
pkgs.python3Packages.pytest pkgs.python3Packages.pytest-timeout
] ++ funAttrs.nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program pytest found: YES' meson-logs/meson-log.txt
${funAttrs.postConfigure or ""}
'';
};
in withSystem funWithTests system;

# All the dependencies including optional ones.
withSystemFull = fun: system: let
funFull = pkgs: let
funAttrs = fun pkgs;
in funAttrs // {
nativeBuildInputs = [
pkgs.asciidoc pkgs.libxslt.bin pkgs.docbook_xml_dtd_45
pkgs.docbook_xsl pkgs.libxml2.bin pkgs.docbook5 pkgs.systemd
] ++ funAttrs.nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program systemd-socket-activate found: YES' \
meson-logs/meson-log.txt
${funAttrs.postConfigure or ""}
'';
};
in withSystemAndTests funFull system;

forEachSystem = f: lib.genAttrs hydraSystems (withSystem f);
testForEachSystem = f: lib.genAttrs hydraSystems (withSystemAndTests f);
fullForEachSystem = f: lib.genAttrs hydraSystems (withSystemFull f);

mkManpageJobs = attrsFun: {
no-manpage = testForEachSystem (pkgs: (attrsFun pkgs) // {
requireManpage = false;
});

asciidoc = {
with-validation = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [
pkgs.libxslt.bin pkgs.docbook_xml_dtd_45 pkgs.docbook_xsl
pkgs.libxml2.bin pkgs.docbook5

# We want to pass the -v argument to a2x so that if we get a
# validation error it's actually shown in the build log. The
# reason we don't do this by default is because it would cause
# unnecessary build output when built on other systems.
(pkgs.runCommand "a2x-wrapped" {
nativeBuildInputs = [ pkgs.makeWrapper ];
a2x = "${pkgs.asciidoc}/bin/a2x";
} ''
mkdir -p "$out/bin"
makeWrapper "$a2x" "$out/bin/a2x" --add-flags -v
ln -s ${lib.escapeShellArg pkgs.asciidoc}/bin/asciidoc \
"$out/bin"
'')
] ++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program xmllint found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});

without-validation = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [
pkgs.asciidoc pkgs.libxslt.bin pkgs.docbook_xml_dtd_45
pkgs.docbook_xsl
] ++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program a2x found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});
};
checks = forAllSystems (system: {
clang-tidy = withSystemFull (pkgs: {
stdenv = pkgs.llvmPackages.stdenv;
nativeBuildInputs = [ pkgs.clang-tools ];
ninjaFlags = [ "clang-tidy" ];
doCheck = false;
doInstallCheck = false;
installPhase = "touch \"$out\"";
}) system;
});

asciidoctor = testForEachSystem (pkgs: (attrsFun pkgs) // {
nativeBuildInputs = [ pkgs.asciidoctor ]
++ (attrsFun pkgs).nativeBuildInputs or [];
postConfigure = ''
grep -qF 'Program asciidoctor found: YES' meson-logs/meson-log.txt
${(attrsFun pkgs).postConfigure or ""}
'';
});
};
hydraJobs.tests = {
basic = let
hydraSystemsAsAttrs = lib.genAttrs hydraSystems lib.id;
checks = builtins.intersectAttrs hydraSystemsAsAttrs self.checks;
transposeSystem = system: lib.mapAttrs (_: lib.nameValuePair system);
transposedChecks = lib.mapAttrsToList transposeSystem checks;
in lib.zipAttrsWith (_: lib.listToAttrs) transposedChecks;

in {
tests.configurations = {
configurations = {
minimal.no-tests = forEachSystem (pkgs: {
requireManpage = false;
nativeBuildInputs = [ pkgs.python3 ];
Expand Down Expand Up @@ -241,7 +263,7 @@
});
};

tests.full = let
full = let
# Like mapAttrsToList but flattens the resulting list.
#
# Type:
Expand Down Expand Up @@ -308,17 +330,17 @@
};
});

tests.repeat100 = fullForEachSystem (pkgs: {
repeat100 = fullForEachSystem (pkgs: {
checkPhase = ''
meson test --print-errorlogs --repeat=100
'';
});

tests.no-hardening = fullForEachSystem (pkgs: {
no-hardening = fullForEachSystem (pkgs: {
hardeningDisable = [ "all" ];
});

tests.vm = let
vm = let
makeTest = path: lib.genAttrs vmTestSystems (system: let
libPath = nixpkgs + "/nixos/lib/testing-python.nix";
testLib = import libPath { inherit system; };
Expand All @@ -328,7 +350,7 @@
systemd-multi = makeTest tests/vm/systemd-multi.nix;
};

tests.programs = let
programs = let
mkProgramTest = system: path: import path {
pkgs = nixpkgs.legacyPackages.${system};
inherit (self.packages.${system}) ip2unix;
Expand All @@ -337,16 +359,7 @@
rsession.x86_64-linux = tests/programs/rsession.nix;
};

tests.clang-tidy = fullForEachSystem (pkgs: {
stdenv = pkgs.llvmPackages.stdenv;
nativeBuildInputs = [ pkgs.clang-tools ];
ninjaFlags = [ "clang-tidy" ];
doCheck = false;
doInstallCheck = false;
installPhase = "touch \"$out\"";
});

tests.sanitizer = lib.mapAttrs (name: let
sanitizer = lib.mapAttrs (name: let
genDrv = { fun ? forEachSystem, override ? x: {} }: fun (super: {
mesonFlags = [ "-Db_sanitize=${name}" ];
mesonBuildType = "debug";
Expand All @@ -366,33 +379,33 @@

undefined.fun = fullForEachSystem;
};
};

coverage = fullForEachSystem (pkgs: {
nativeBuildInputs = [ pkgs.lcov ];
hydraJobs.coverage = fullForEachSystem (pkgs: {
nativeBuildInputs = [ pkgs.lcov ];

mesonFlags = [ "-Db_coverage=true" ];
mesonFlags = [ "-Db_coverage=true" ];

installPhase = ''
ninja coverage-html 2>&1 | tee metrics.log >&2
installPhase = ''
ninja coverage-html 2>&1 | tee metrics.log >&2
mkdir -p "$out/nix-support"
sed -n -e '/^Overall coverage rate:$/,/^[^ ]/ {
s/^ \+lines\.*: \([0-9.]\+\)%.*/lineCoverage \1 %/p
s/^ \+functions\.*: \([0-9.]\+\)%.*/functionCoverage \1 %/p
}' metrics.log > "$out/nix-support/hydra-metrics"
mkdir -p "$out/nix-support"
sed -n -e '/^Overall coverage rate:$/,/^[^ ]/ {
s/^ \+lines\.*: \([0-9.]\+\)%.*/lineCoverage \1 %/p
s/^ \+functions\.*: \([0-9.]\+\)%.*/functionCoverage \1 %/p
}' metrics.log > "$out/nix-support/hydra-metrics"
if $(wc -l < "$out/nix-support/hydra-metrics") -ne 2; then
echo "Failed to get coverage statistics." >&2
exit 1
fi
if $(wc -l < "$out/nix-support/hydra-metrics") -ne 2; then
echo "Failed to get coverage statistics." >&2
exit 1
fi
mv meson-logs/coveragereport "$out/coverage"
echo "report coverage $out/coverage" \
> "$out/nix-support/hydra-build-products"
'';
mv meson-logs/coveragereport "$out/coverage"
echo "report coverage $out/coverage" \
> "$out/nix-support/hydra-build-products"
'';

doInstallCheck = false;
});
};
doInstallCheck = false;
});
};
}

0 comments on commit 53a8451

Please sign in to comment.