f2 feat(log): add repository argument (#4)

* fix(search): remove body param

* feat(search): add repo filter

* feat(log): add repository argument

* chore: gitignore vscode

* chore: delete .vscode

* feat(annotate): add repository argument
This commit is contained in:
Luis H. Ball Jr 2021-11-04 21:18:28 -07:00 committed by GitHub
parent d6aa8192ed
commit 8fdba69645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 7 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
.vscode

View File

@ -1,3 +0,0 @@
{
"workbench.colorTheme": "Ayu Mirage Bordered"
}

View File

@ -44,7 +44,47 @@ pub async fn fetch_pull_requests_matching(
&credentials, &credentials,
"https://api.github.com/search/issues", "https://api.github.com/search/issues",
) )
.query(&[("q", format!("\"{}\" in:title,body", pattern))]); .query(&[("q", format!("{} in:title", pattern))]);
let items = request.send().await?.json::<SearchResponse>().await?.items;
let item_futures = items.into_iter().map(|item| {
api::base_request(&client, &credentials, &item.url.replace("issues", "pulls")).send()
});
// The `unwrap`s are required here because both `reqwest::send` and `reqwest::json` return a `Result` which has
// to be unwrapped after the future has been `await`ed on.
let items = join_all(item_futures)
.await
.into_iter()
.map(|item| item.unwrap());
let responses: Vec<_> = join_all(items.map(|item| item.json::<PullRequest>()))
.await
.into_iter()
.map(|item| async {
let pr = item.unwrap();
let pr = pr.fetch_reviews(credentials).await.unwrap();
pr
})
.collect();
Ok(join_all(responses).await)
}
pub async fn fetch_matching_pull_requests_from_repository(
pattern: &str,
repository: &str,
credentials: &Credentials,
) -> Result<Vec<PullRequest>, Box<dyn Error>> {
let client = reqwest::Client::new();
let request = api::base_request(
&client,
&credentials,
"https://api.github.com/search/issues",
)
.query(&[("q", format!("{} in:title repo:{}", pattern, repository))]);
let items = request.send().await?.json::<SearchResponse>().await?.items; let items = request.send().await?.json::<SearchResponse>().await?.items;

View File

@ -17,6 +17,12 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.required(true) .required(true)
.help("All pull requests containing this identifier in their title form a stack"); .help("All pull requests containing this identifier in their title form a stack");
let repository = Arg::with_name("repository")
.long("repository")
.short("r")
.takes_value(true)
.help("Remote repository to filter identifier search results by");
let exclude = Arg::with_name("exclude") let exclude = Arg::with_name("exclude")
.long("excl") .long("excl")
.short("e") .short("e")
@ -29,6 +35,7 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.setting(AppSettings::ArgRequiredElseHelp) .setting(AppSettings::ArgRequiredElseHelp)
.arg(identifier.clone()) .arg(identifier.clone())
.arg(exclude.clone()) .arg(exclude.clone())
.arg(repository.clone())
.arg(Arg::with_name("prelude") .arg(Arg::with_name("prelude")
.long("prelude") .long("prelude")
.short("p") .short("p")
@ -39,7 +46,8 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.about("Print a list of all pull requests in a stack to STDOUT") .about("Print a list of all pull requests in a stack to STDOUT")
.setting(AppSettings::ArgRequiredElseHelp) .setting(AppSettings::ArgRequiredElseHelp)
.arg(exclude.clone()) .arg(exclude.clone())
.arg(identifier.clone()); .arg(identifier.clone())
.arg(repository.clone());
let autorebase = SubCommand::with_name("autorebase") let autorebase = SubCommand::with_name("autorebase")
.about("Rebuild a stack based on changes to local branches and mirror these changes up to the remote") .about("Rebuild a stack based on changes to local branches and mirror these changes up to the remote")
@ -100,6 +108,24 @@ async fn build_pr_stack(
Ok(stack) Ok(stack)
} }
async fn build_pr_stack_for_repo(
pattern: &str,
repository: &str,
credentials: &Credentials,
exclude: Vec<String>,
) -> Result<FlatDep, Box<dyn Error>> {
let prs = api::search::fetch_matching_pull_requests_from_repository(pattern, repository, &credentials).await?;
let prs = prs
.into_iter()
.filter(|pr| !exclude.contains(&pr.number().to_string()))
.map(Rc::new)
.collect::<Vec<Rc<PullRequest>>>();
let graph = graph::build(&prs);
let stack = graph::log(&graph);
Ok(stack)
}
fn get_excluded(m: &ArgMatches) -> Vec<String> { fn get_excluded(m: &ArgMatches) -> Vec<String> {
let excluded = m.values_of("exclude"); let excluded = m.values_of("exclude");
@ -120,7 +146,19 @@ async fn main() -> Result<(), Box<dyn Error>> {
match matches.subcommand() { match matches.subcommand() {
("annotate", Some(m)) => { ("annotate", Some(m)) => {
let identifier = m.value_of("identifier").unwrap(); let identifier = m.value_of("identifier").unwrap();
let stack = build_pr_stack(identifier, &credentials, get_excluded(m)).await?; // If no repository is specified, use build_pr_stack. Otherwise, use
// build_pr_stack_for_repo.
let stack = if m.value_of("repository").is_none() {
build_pr_stack(identifier, &credentials, get_excluded(m)).await?
} else {
let repository = m.value_of("repository").unwrap();
println!(
"Searching for {} identifier in {} repo",
style(identifier).bold(),
style(repository).bold()
);
build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)).await?
};
let table = markdown::build_table(&stack, identifier, m.value_of("prelude")); let table = markdown::build_table(&stack, identifier, m.value_of("prelude"));
for (pr, _) in stack.iter() { for (pr, _) in stack.iter() {
@ -135,7 +173,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
("log", Some(m)) => { ("log", Some(m)) => {
let identifier = m.value_of("identifier").unwrap(); let identifier = m.value_of("identifier").unwrap();
let stack = build_pr_stack(identifier, &credentials, get_excluded(m)).await?;
// If no repository is specified, use build_pr_stack. Otherwise, use
// build_pr_stack_for_repo.
let stack = if m.value_of("repository").is_none() {
build_pr_stack(identifier, &credentials, get_excluded(m)).await?
} else {
let repository = m.value_of("repository").unwrap();
println!(
"Searching for {} identifier in {} repo",
style(identifier).bold(),
style(repository).bold()
);
build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)).await?
};
for (pr, maybe_parent) in stack { for (pr, maybe_parent) in stack {
match maybe_parent { match maybe_parent {