get the tree data structure working (finally)

This commit is contained in:
Timothy Andrew 2020-06-02 23:21:17 +05:30
parent cccab03886
commit 2371324cf3
No known key found for this signature in database
GPG Key ID: ABD64509E977B249
7 changed files with 69 additions and 31 deletions

17
Cargo.lock generated
View File

@ -79,6 +79,12 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -227,6 +233,7 @@ name = "gh-stack"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"futures", "futures",
"petgraph",
"reqwest", "reqwest",
"serde", "serde",
"tokio", "tokio",
@ -575,6 +582,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "0.4.17" version = "0.4.17"

View File

@ -11,3 +11,4 @@ reqwest = { version = "0.10.6", features = ["json"] }
tokio = { version = "0.2", features = ["full"] } tokio = { version = "0.2", features = ["full"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
futures = "0.3.5" futures = "0.3.5"
petgraph = "0.5"

View File

@ -2,26 +2,28 @@ use futures::future::join_all;
use serde::Deserialize; use serde::Deserialize;
use std::error::Error; use std::error::Error;
use crate::{api, Credentials}; use crate::{api, markdown, Credentials};
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug, Clone)]
pub struct SearchItem { pub struct SearchItem {
url: String, url: String,
title: String, title: String,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug, Clone)]
pub struct PullRequestRef { pub struct PullRequestRef {
label: String, label: String,
r#ref: String, r#ref: String,
sha: String, sha: String,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug, Clone)]
pub struct PullRequest { pub struct PullRequest {
id: usize, id: usize,
number: usize,
head: PullRequestRef, head: PullRequestRef,
base: PullRequestRef, base: PullRequestRef,
merges_into: Option<Box<PullRequest>>,
title: String, title: String,
} }
@ -33,7 +35,21 @@ impl PullRequest {
pub fn base(&self) -> &str { pub fn base(&self) -> &str {
&self.base.label &self.base.label
} }
pub fn set_merges_into(&mut self, into: PullRequest) {
// `clone` here to avoid an explosion of lifetime specifiers
self.merges_into = Some(Box::new(into))
} }
}
// impl markdown::AsMarkdown for PullRequest {
// fn as_markdown_table_row(&self) -> String {
// match self.merges_into {
// Some(into) => format!("|#{}|{}|#{}|", self.number, self.title, into.number),
// None => format!("|#{}|{}|`develop`/feature branch|", self.number, self.title),
// }
// }
// }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct SearchResponse { struct SearchResponse {

View File

@ -1,34 +1,23 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use petgraph::visit::IntoNodeReferences;
use std::rc::Rc;
use std::cell::RefCell;
use petgraph::Graph;
use crate::api::search::PullRequest; use crate::api::search::PullRequest;
pub fn build(prs: &[PullRequest]) { pub fn build(prs: Vec<Rc<PullRequest>>) -> Graph<Rc<PullRequest>, usize> {
let mut heads = HashSet::new(); let mut tree = Graph::<Rc<PullRequest>, usize>::new();
let mut prs_by_base = HashMap::new(); let heads = prs.iter().map(|pr| pr.head());
let handles: Vec<_> = prs.iter().map(|pr| tree.add_node(pr.clone())).collect();
let handles_by_head: HashMap<_, _> = heads.zip(handles.iter()).collect();
for pr in prs.iter() { for (i, pr) in prs.iter().enumerate() {
heads.insert(pr.head()); let head_handle = handles[i];
let entry = prs_by_base.entry(pr.base()).or_insert(Vec::new()); if let Some(&base_handle) = handles_by_head.get(pr.base()) {
entry.push(pr); tree.add_edge(head_handle, *base_handle, 1);
}
let roots: Vec<&PullRequest> = prs.iter().filter(|pr| !heads.contains(pr.base())).collect();
let results = resolve(&roots, &prs_by_base);
}
fn resolve<'a>(
roots: &Vec<&'a PullRequest>,
prs_by_base: &'a HashMap<&str, Vec<&PullRequest>>
) -> Vec<&'a PullRequest> {
let mut results = Vec::new();
for &root in roots.iter() {
results.push(root);
if let Some(children) = prs_by_base.get(root.head()) {
let mut children = resolve(children, prs_by_base);
results.append(&mut children);
} }
} }
results tree
} }

View File

@ -1,5 +1,6 @@
pub mod api; pub mod api;
pub mod graph; pub mod graph;
pub mod markdown;
pub struct Credentials { pub struct Credentials {
// Personal access token // Personal access token

View File

@ -1,10 +1,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::process; use std::process;
use gh_stack::api; use gh_stack::api;
use gh_stack::graph; use gh_stack::graph;
use gh_stack::markdown;
use gh_stack::Credentials; use gh_stack::Credentials;
#[tokio::main] #[tokio::main]
@ -25,7 +27,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
let credentials = Credentials::new(token); let credentials = Credentials::new(token);
let prs = api::search::fetch_pull_requests_matching(&pattern, &credentials).await?; let prs = api::search::fetch_pull_requests_matching(&pattern, &credentials).await?;
graph::build(&prs); let prs = prs.into_iter().map(|pr| Rc::new(pr)).collect();
let tree = graph::build(prs);
println!("{:?}", tree);
// markdown::build_table(&graph[..]);
Ok(()) Ok(())
/* /*

8
src/markdown.rs Normal file
View File

@ -0,0 +1,8 @@
use crate::api::search::PullRequest;
use std::fmt::Display;
pub trait AsMarkdown {
fn as_markdown_table_row(&self) -> String;
}
pub fn build_table<T: Display>(graph: &[T]) {}