grit/trunk.rs
1use std::fmt;
2
3use crate::git::git;
4
5/// No local branch was found to have any of the supplied names.
6#[derive(Debug)]
7pub struct Error(Vec<String>);
8
9impl fmt::Display for Error {
10 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
11 write!(f, "trunk not found: {}", self.0.join(", "))
12 }
13}
14
15/// Default names to consider when searching for local trunk branch, in order of
16/// preference. Overridden by the value of the [`GRIT_TRUNKS`] environment
17/// variable.
18pub const DEFAULT_TRUNKS: [&str; 2] = ["main", "master"];
19
20/// Environment variable to check for comma-separated list of local trunk branch
21/// names. If the variable is unset, the value defaults to [`DEFAULT_TRUNKS`].
22///
23/// TODO: In Jujutsu repos, use JJ's notion of trunk:
24/// ```sh
25/// jj log --no-graph --revision 'trunk()' --template 'bookmarks'
26/// ```
27pub const GRIT_TRUNKS: &str = "GRIT_TRUNKS";
28
29/// Returns the names of potential trunk branches, per [`GRIT_TRUNKS`] (if set)
30/// or [`DEFAULT_TRUNKS`].
31pub fn names() -> Vec<String> {
32 let trunks = std::env::var(GRIT_TRUNKS);
33 match trunks.as_ref() {
34 Ok(trunks) => trunks.split(',').map(str::to_owned).collect(),
35 Err(_) => DEFAULT_TRUNKS.map(str::to_owned).to_vec(),
36 }
37}
38
39/// Returns the name of the local trunk branch, if it can be determined.
40///
41/// # Errors
42///
43/// Will return [`Error`] if no local trunk branch is found.
44pub async fn local() -> Result<String, Error> {
45 let names = names();
46 for name in &names {
47 if git(["show-ref", name]).await.is_ok() {
48 return Ok(name.to_owned());
49 }
50 }
51 Err(Error(names))
52}