Skip to content

Commit

Permalink
Added branches subcommand
Browse files Browse the repository at this point in the history
Added the branches subcommand which will print out all projects that
have a topic branch in their repo. This makes it very easy to find
which repos have what topic branches and pairs with the checkout
subcommand which allows developers to easily switch between their
cross repo changes and check on the status of these changes.
  • Loading branch information
Stefan Bossbaly authored and StefanBossbaly committed Sep 18, 2024
1 parent 01bad4c commit 69b7560
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 4 deletions.
49 changes: 49 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ enum Commands {
local: bool,
},

/// List the topic branches
Branches {},

/// Checkout a new tree into a new directory
Clone {
/// The target to checkout in the format <REMOTE>[/<BRANCH>[:MANIFEST]]
Expand Down Expand Up @@ -392,6 +395,7 @@ impl std::fmt::Display for Commands {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Commands::Init { .. } => write!(f, "init"),
Commands::Branches { .. } => write!(f, "branches"),
Commands::Clone { .. } => write!(f, "clone"),
Commands::Fetch { .. } => write!(f, "fetch"),
Commands::Sync { .. } => write!(f, "sync"),
Expand Down Expand Up @@ -447,6 +451,47 @@ fn parse_group_filters(group_filters: &str) -> Vec<GroupFilter> {
group_filters
}

fn cmd_branches(config: Config, pool: &mut Pool, tree: &Tree) -> Result<i32, Error> {
let results = tree.branches(config, pool)?;

if results.failed.is_empty() {
let projects_with_topic_branch = results.successful.into_iter().filter_map(|execution_result| {
if execution_result.result.branches.is_empty() {
Some(execution_result.result)
} else {
None
}
});

for project in projects_with_topic_branch {
println!(
"{}: {}",
project.name,
project
.branches
.iter()
.map(|branch| {
if branch.is_head {
format!("*{}", branch.name)
} else {
branch.name.clone()
}
})
.collect::<Vec<_>>()
.join(", ")
);
}

Ok(0)
} else {
for error in results.failed {
eprintln!("{}: {}", error.name, error.result);
}

Ok(1)
}
}

fn cmd_clone(
config: &Config,
pool: &mut Pool,
Expand Down Expand Up @@ -976,6 +1021,10 @@ fn main() {
fetch,
)
}
Commands::Branches {} => {
let tree = Tree::find_from_path(cwd)?;
cmd_branches(config, &mut pool, &tree)
}
Commands::Clone {
target,
directory,
Expand Down
63 changes: 59 additions & 4 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,18 @@ pub struct ProjectStatus {
pub behind: usize,
}

#[derive(Debug)]
pub struct ProjectBranchStatus {
pub name: String,
pub branches: Vec<BranchStatus>,
}

#[derive(Debug)]
pub struct BranchStatus {
pub name: String,
pub is_head: bool,
}

pub struct BranchInfo<'repo> {
pub name: String,
pub commit: git2::Commit<'repo>,
Expand Down Expand Up @@ -805,10 +817,12 @@ impl Tree {
}

// Do a dry run first to look for dirty changes.
repo.checkout_tree(
new_head.as_object(),
Some(git2::build::CheckoutBuilder::new().dry_run()),
).context(format!("failed to dry run checkout to {:?}", new_head))?;
repo
.checkout_tree(
new_head.as_object(),
Some(git2::build::CheckoutBuilder::new().dry_run()),
)
.context(format!("failed to dry run checkout to {:?}", new_head))?;

repo
.checkout_tree(new_head.as_object(), None)
Expand Down Expand Up @@ -1157,6 +1171,47 @@ impl Tree {
Ok(0)
}

pub fn branches(
&self,
config: Config,
pool: &mut Pool,
) -> Result<ExecutionResults<ProjectBranchStatus, Error>, Error> {
let projects = self.collect_manifest_projects(&config, &self.read_manifest()?, None, None)?;

let mut job = Job::with_name("branches");

for project in projects {
job.add_task(
project.project_path.clone(),
move || -> Result<ProjectBranchStatus, Error> {
let repo = git2::Repository::open(self.path.join(&project.project_path))
.context(format!("failed to open object repository {:?}", project.project_path))?;

let topic_branch_results = repo.branches(Some(git2::BranchType::Local))?;
let mut branches = Vec::new();

for topic_branch_result in topic_branch_results {
let (topic_branch, _) = topic_branch_result?;
branches.push(BranchStatus {
name: topic_branch
.name()?
.expect("Branch should have utf-8 encoded name")
.to_owned(),
is_head: topic_branch.is_head(),
});
}

Ok(ProjectBranchStatus {
name: project.project_name.clone(),
branches,
})
},
);
}

Ok(pool.execute(job))
}

pub fn status(
&self,
config: &Config,
Expand Down

0 comments on commit 69b7560

Please sign in to comment.