Merge pull request #59 from NixOS/auto-tag-topic-issue-56

Auto tag topic issue 56
This commit is contained in:
Graham Christensen 2018-02-03 12:17:18 -05:00 committed by GitHub
commit a2d29c0de7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 197 additions and 3 deletions

View file

@ -40,6 +40,18 @@
"zimbatm"
]
},
"tag_paths": {
"6.topic: python": [
"pkgs/top-level/python-packages.nix",
"pkgs/development/interpreters/python",
"pkgs/development/python-modules",
"doc/languages-frameworks/python.md"
],
"6.topic: ruby": [
"pkgs/development/interpreters/ruby",
"pkgs/development/ruby-modules"
]
},
"checkout": {
"root": "/var/lib/gc-of-borg/.nix-test-rs"
},

View file

@ -39,6 +39,7 @@ fn main() {
cfg.acl(),
cfg.runner.identity.clone(),
events,
cfg.tag_paths.clone().unwrap(),
);
channel.basic_prefetch(1).unwrap();

View file

@ -148,7 +148,6 @@ impl CachedProjectCo {
}
}
pub fn commit_messages_from_head(&self, commit: &str) -> Result<Vec<String>, Error> {
let mut lock = self.lock()?;
@ -175,6 +174,33 @@ impl CachedProjectCo {
));
}
}
pub fn files_changed_from_head(&self, commit: &str) -> Result<Vec<String>, Error> {
let mut lock = self.lock()?;
let result = Command::new("git")
.arg("diff")
.arg("--name-only")
.arg(format!("HEAD...{}", commit))
.current_dir(self.clone_to())
.output()?;
lock.unlock();
if result.status.success() {
return Ok(
String::from_utf8_lossy(&result.stdout)
.lines()
.map(|l| l.to_owned())
.collect(),
);
} else {
return Err(Error::new(
ErrorKind::Other,
String::from_utf8_lossy(&result.stderr).to_lowercase(),
));
}
}
}
impl clone::GitClonable for CachedProjectCo {
@ -264,7 +290,9 @@ mod tests {
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"));
working_co
.checkout_origin_ref(OsStr::new("master"))
.unwrap();
let expect: Vec<String> = vec!["check out this cool PR".to_owned()];
@ -275,4 +303,31 @@ mod tests {
expect
);
}
#[test]
pub fn test_files_changed_list() {
let workingdir = TestScratch::new_dir("test-test-files-changed-list");
let bare = TestScratch::new_dir("bare-files-changed");
let mk_co = TestScratch::new_dir("mk-files-changed");
let hash = make_pr_repo(&bare.path(), &mk_co.path());
let cloner = cached_cloner(&workingdir.path());
let project = cloner.project("commit-files-changed-list".to_owned(), bare.string());
let working_co = project
.clone_for("testing-files-changed".to_owned(), "123".to_owned())
.expect("clone should work");
working_co
.checkout_origin_ref(OsStr::new("master"))
.unwrap();
let expect: Vec<String> = vec!["default.nix".to_owned(), "hi another file".to_owned()];
assert_eq!(
working_co.files_changed_from_head(&hash).expect(
"fetching files changed should work",
),
expect
);
}
}

View file

@ -7,6 +7,7 @@ use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hubcaps::{Credentials, Github};
use nix::Nix;
use std::collections::HashMap;
use ofborg::acl;
@ -20,6 +21,7 @@ pub struct Config {
pub rabbitmq: RabbitMQConfig,
pub github: Option<GithubConfig>,
pub log_storage: Option<LogStorage>,
pub tag_paths: Option<HashMap<String, Vec<String>>>,
}
#[derive(Serialize, Deserialize, Debug)]

View file

@ -1,5 +1,6 @@
use ofborg::tasks;
use ofborg::outpathdiff::PackageArch;
use std::collections::HashMap;
pub struct StdenvTagger {
possible: Vec<String>,
@ -154,3 +155,104 @@ impl RebuildTagger {
}
}
pub struct PathsTagger {
possible: HashMap<String, Vec<String>>,
selected: Vec<String>,
}
impl PathsTagger {
pub fn new(tags_and_criteria: HashMap<String, Vec<String>>) -> PathsTagger {
PathsTagger {
possible: tags_and_criteria,
selected: vec![],
}
}
pub fn path_changed(&mut self, path: &str) {
let mut tags_to_add: Vec<String> = self.possible
.iter()
.filter(|&(ref tag, ref _paths)| !self.selected.contains(&tag))
.filter(|&(ref _tag, ref paths)| {
paths.iter().any(|tp| path.contains(tp))
})
.map(|(tag, _paths)| tag.clone())
.collect();
self.selected.append(&mut tags_to_add);
self.selected.sort();
}
pub fn tags_to_add(&self) -> Vec<String> {
self.selected.clone()
}
pub fn tags_to_remove(&self) -> Vec<String> {
let mut remove: Vec<String> = self.possible.keys().map(|k| k.to_owned()).collect();
remove.sort();
for tag in &self.selected {
let pos = remove.binary_search(&tag).unwrap();
remove.remove(pos);
}
return remove;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_files_changed_list() {
let mut criteria: HashMap<String, Vec<String>> = HashMap::new();
criteria.insert(
"topic: python".to_owned(),
vec![
"pkgs/top-level/python-packages.nix".to_owned(),
"bogus".to_owned(),
],
);
criteria.insert(
"topic: ruby".to_owned(),
vec![
"pkgs/development/interpreters/ruby".to_owned(),
"bogus".to_owned(),
],
);
{
let mut tagger = PathsTagger::new(criteria.clone());
tagger.path_changed("default.nix");
assert_eq!(tagger.tags_to_add().len(), 0);
assert_eq!(
tagger.tags_to_remove(),
vec!["topic: python".to_owned(), "topic: ruby".to_owned()]
);
tagger.path_changed("pkgs/development/interpreters/ruby/default.nix");
assert_eq!(tagger.tags_to_add(), vec!["topic: ruby".to_owned()]);
assert_eq!(tagger.tags_to_remove(), vec!["topic: python".to_owned()]);
tagger.path_changed("pkgs/development/interpreters/ruby/foobar.nix");
assert_eq!(tagger.tags_to_add(), vec!["topic: ruby".to_owned()]);
assert_eq!(tagger.tags_to_remove(), vec!["topic: python".to_owned()]);
tagger.path_changed("pkgs/top-level/python-packages.nix");
assert_eq!(
tagger.tags_to_add(),
vec!["topic: python".to_owned(), "topic: ruby".to_owned()]
);
}
{
let mut tagger = PathsTagger::new(criteria.clone());
tagger.path_changed("bogus");
assert_eq!(
tagger.tags_to_add(),
vec!["topic: python".to_owned(), "topic: ruby".to_owned()]
);
}
}
}

View file

@ -15,7 +15,7 @@ use ofborg::nix::Nix;
use ofborg::acl::ACL;
use ofborg::stats;
use ofborg::worker;
use ofborg::tagger::{StdenvTagger, RebuildTagger};
use ofborg::tagger::{StdenvTagger, RebuildTagger, PathsTagger};
use ofborg::outpathdiff::{OutPaths, OutPathDiff};
use ofborg::evalchecker::EvalChecker;
use ofborg::commitstatus::CommitStatus;
@ -30,6 +30,7 @@ pub struct MassRebuildWorker<E> {
acl: ACL,
identity: String,
events: E,
tag_paths: HashMap<String, Vec<String>>,
}
impl<E: stats::SysEvents> MassRebuildWorker<E> {
@ -40,6 +41,7 @@ impl<E: stats::SysEvents> MassRebuildWorker<E> {
acl: ACL,
identity: String,
events: E,
tag_paths: HashMap<String, Vec<String>>,
) -> MassRebuildWorker<E> {
return MassRebuildWorker {
cloner: cloner,
@ -48,12 +50,27 @@ impl<E: stats::SysEvents> MassRebuildWorker<E> {
acl: acl,
identity: identity,
events: events,
tag_paths: tag_paths
};
}
fn actions(&self) -> massrebuildjob::Actions {
return massrebuildjob::Actions {};
}
fn tag_from_paths(&self, issue: &hubcaps::issues::IssueRef, paths: Vec<String>) {
let mut tagger = PathsTagger::new(self.tag_paths.clone());
for path in paths {
tagger.path_changed(&path);
}
update_labels(
&issue,
tagger.tags_to_add(),
tagger.tags_to_remove(),
);
}
}
impl<E: stats::SysEvents> worker::SimpleWorker for MassRebuildWorker<E> {
@ -199,6 +216,11 @@ impl<E: stats::SysEvents> worker::SimpleWorker for MassRebuildWorker<E> {
vec!["".to_owned()],
));
self.tag_from_paths(
&issue,
co.files_changed_from_head(&job.pr.head_sha).unwrap_or(vec![])
);
overall_status.set_with_description("Merging PR", hubcaps::statuses::State::Pending);
if let Err(_) = co.merge_commit(job.pr.head_sha.as_ref()) {