qlty_analysis/git/
upstream.rs

1use anyhow::Result;
2use git2::Repository;
3use qlty_config::Workspace;
4use tracing::{info, debug};
5
6pub fn compute_upstream(workspace: &Workspace, specified: &Option<String>) -> Option<String> {
7    if let Some(specified) = specified {
8        Some(specified.to_owned())
9    } else if let Ok(upstream) = infer_upstream(workspace) {
10        info!("Inferred upstream: {:?}", upstream);
11        upstream
12    } else {
13        None
14    }
15}
16
17fn find_remote_default_branch(repo: &Repository) -> Option<String> {
18    if let Ok(_) = repo.find_remote("origin") {
19        if let Ok(head) = repo.find_reference("refs/remotes/origin/HEAD") {
20            if let Some(target) = head.symbolic_target() {
21                return Some(target.replace("refs/remotes/", ""));
22            }
23            debug!("Target not found for HEAD");
24        }
25    }
26
27    None
28}
29
30fn infer_upstream(workspace: &Workspace) -> Result<Option<String>> {
31    let repo = workspace.repo()?;
32
33    match find_remote_default_branch(&repo) {
34        Some(branch) => Ok(Some(branch)),
35        None => {
36            debug!("Could not find HEAD branch for remote 'origin'. Checking for main/master/develop.");
37            default_upstream(&repo)
38        },
39    }
40}
41
42fn default_upstream(repo: &Repository) -> Result<Option<String>> {
43    let known_default_branches = vec!["main", "master", "develop"];
44
45    for branch_name in known_default_branches.iter() {
46        if repo.find_branch(&branch_name, git2::BranchType::Local).is_ok() {
47            debug!("Found {} branch. Using as upstream.", branch_name);
48            return Ok(Some(branch_name.to_string()));
49        }
50    };
51
52    debug!("No main/master/develop branch found.");
53    Ok(None)
54}