From 5b6a387fee9f99b80509f954c8c06903b7a005d7 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Tue, 1 Jan 2019 15:44:22 -0500 Subject: [PATCH] Calculate maintainers --- ofborg/src/lib.rs | 1 + ofborg/src/maintainers.nix | 110 +++++++++++++++++++++++++++++++++++++ ofborg/src/maintainers.rs | 84 ++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 ofborg/src/maintainers.nix create mode 100644 ofborg/src/maintainers.rs diff --git a/ofborg/src/lib.rs b/ofborg/src/lib.rs index 4aa6b67..eae41fc 100644 --- a/ofborg/src/lib.rs +++ b/ofborg/src/lib.rs @@ -39,6 +39,7 @@ pub mod evalchecker; pub mod files; pub mod ghevent; pub mod locks; +pub mod maintainers; pub mod message; pub mod nix; pub mod notifyworker; diff --git a/ofborg/src/maintainers.nix b/ofborg/src/maintainers.nix new file mode 100644 index 0000000..3bb01a2 --- /dev/null +++ b/ofborg/src/maintainers.nix @@ -0,0 +1,110 @@ +{ changedattrsjson, changedpathsjson }: +let + pkgs = import ./. {}; + + changedattrs = builtins.fromJSON changedattrsjson; + changedpaths = builtins.fromJSON changedpathsjson; + + anyMatchingFile = filename: + let + matching = builtins.filter + (changed: pkgs.lib.strings.hasSuffix changed filename) + changedpaths; + in (builtins.length matching) > 0; + + anyMatchingFiles = files: + (builtins.length (builtins.filter anyMatchingFile files)) > 0; + + enrichedAttrs = builtins.map + (path: { + path = path; + name = "pkgs.${builtins.concatStringsSep "." path}"; + }) + changedattrs; + +validPackageAttributes = builtins.filter + (pkg: + if (pkgs.lib.attrsets.hasAttrByPath pkg.path pkgs) then + (if (builtins.tryEval (pkgs.lib.attrsets.attrByPath pkg.path null pkgs)).success + then true + else builtins.trace "Failed to access ${pkg.name} even though it exists" false) + else builtins.trace "Failed to locate ${pkg.name}." false + ) + enrichedAttrs; + + attrsWithPackages = builtins.map + (pkg: pkg // { package = pkgs.lib.attrsets.attrByPath pkg.path null pkgs; }) + validPackageAttributes; + +attrsWithMaintainers = builtins.map + (pkg: pkg // { maintainers = (pkg.package.meta or {}).maintainers or []; }) + attrsWithPackages; + +attrsWeCanPing = builtins.filter + (pkg: if (builtins.length pkg.maintainers) > 0 + then true + else builtins.trace "Package has no maintainers: ${pkg.name}" false + ) + attrsWithMaintainers; + +relevantFilenames = drv: + (pkgs.lib.lists.unique + (builtins.map + (pos: pos.file) + (builtins.filter (x: x != null) + [ + (builtins.unsafeGetAttrPos "maintainers" (drv.meta or {})) + (builtins.unsafeGetAttrPos "src" drv) + # broken because name is always set in stdenv: + # # A hack to make `nix-env -qa` and `nix search` ignore broken packages. + # # TODO(@oxij): remove this assert when something like NixOS/nix#1771 gets merged into nix. + # name = assert validity.handled; name + lib.optionalString + #(builtins.unsafeGetAttrPos "name" drv) + (builtins.unsafeGetAttrPos "pname" drv) + (builtins.unsafeGetAttrPos "version" drv) + ] + ))); + +attrsWithFilenames = builtins.map + (pkg: pkg // { filenames = relevantFilenames pkg.package; }) + attrsWithMaintainers; + +attrsWithModifiedFiles = builtins.filter + (pkg: anyMatchingFiles pkg.filenames) + attrsWithFilenames; + +listToPing = pkgs.lib.lists.flatten + (builtins.map + (pkg: + builtins.map + (maintainer: { + handle = maintainer.github; + packageName = pkg.name; + dueToFiles = pkg.filenames; + }) + pkg.maintainers + ) + attrsWithModifiedFiles); + +byMaintainer = pkgs.lib.lists.foldr + (ping: collector: collector // { "${ping.handle}" = [ { inherit (ping) packageName dueToFiles; } ] ++ (collector."${ping.handle}" or []); }) + {} + listToPing; + +textForPackages = packages: + pkgs.lib.strings.concatStringsSep ", " ( + builtins.map + (pkg: pkg.packageName) + packages); + +textPerMaintainer = pkgs.lib.attrsets.mapAttrs + (maintainer: packages: "- @${maintainer} for ${textForPackages packages}") + byMaintainer; + + packagesPerMaintainer = pkgs.lib.attrsets.mapAttrs + (maintainer: packages: + builtins.map + (pkg: pkg.packageName) + packages) + byMaintainer; +in packagesPerMaintainer diff --git a/ofborg/src/maintainers.rs b/ofborg/src/maintainers.rs new file mode 100644 index 0000000..d88e918 --- /dev/null +++ b/ofborg/src/maintainers.rs @@ -0,0 +1,84 @@ +use std::collections::HashMap; + +#[derive(Deserialize, Debug, Eq, PartialEq)] +struct ImpactedMaintainers(HashMap>); +#[derive(Deserialize, Debug, Eq, PartialEq, Hash)] +struct Maintainer(String); +impl<'a> From<&'a str> for Maintainer { + fn from(name: &'a str) -> Maintainer { + Maintainer(name.to_owned()) + } +} +#[derive(Deserialize, Debug, Eq, PartialEq, Hash)] +struct Package(String); +impl<'a> From<&'a str> for Package { + fn from(name: &'a str) -> Package { + Package(name.to_owned()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use checkout::cached_cloner; + use clone::GitClonable; + use ofborg::nix::Nix; + use std::env; + use std::ffi::OsStr; + use std::path::{Path, PathBuf}; + + fn tpath(component: &str) -> PathBuf { + return Path::new(env!("CARGO_MANIFEST_DIR")).join(component); + } + + #[test] + fn example() { + let attributes = vec![vec!["kgpg"], vec!["qrencode"], vec!["pass"]]; + + let cloner = cached_cloner(&tpath("nixpkgs")); + let project = cloner.project( + "commit-msg-list".to_owned(), + "https://github.com/nixos/nixpkgs.git".to_owned(), + ); + + let working_co = project + .clone_for("testing-commit-msgs".to_owned(), "123".to_owned()) + .expect("clone should work"); + + working_co + .checkout_origin_ref(OsStr::new("master")) + .unwrap(); + + working_co.fetch_pr(53149).unwrap(); + + let paths = working_co.files_changed_from_head("pr").unwrap(); + let pathstr = serde_json::to_string(&paths).unwrap(); + let attrstr = serde_json::to_string(&attributes).unwrap(); + + let mut argstrs: HashMap<&str, &str> = HashMap::new(); + argstrs.insert("changedattrsjson", &attrstr); + argstrs.insert("changedpathsjson", &pathstr); + + let remote = env::var("NIX_REMOTE").unwrap_or("".to_owned()); + let nix = Nix::new("x86_64-linux".to_owned(), remote, 1800, None); + let ret = nix + .safely_evaluate_expr_cmd( + &working_co.clone_to(), + include_str!("./maintainers.nix"), + argstrs, + ) + .output() + .expect(":)"); + + let parsed: ImpactedMaintainers = + serde_json::from_str(&String::from_utf8(ret.stdout).unwrap()).unwrap(); + + let mut expect = ImpactedMaintainers(HashMap::new()); + expect.0.insert( + Maintainer::from("yegortimoshenko"), + vec![Package::from("pkgs.qrencode")], + ); + + assert_eq!(parsed, expect); + } +}