Skip to content

Commit

Permalink
Merge pull request #37 from emberist/feat/add-a-way-to-check-exists-m…
Browse files Browse the repository at this point in the history
…rburns-branches

Add a way to check exists mrburns branches
  • Loading branch information
emberist authored Jun 20, 2024
2 parents 8841cce + ece9d6e commit 6521cf9
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 39 deletions.
2 changes: 2 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum Commands {
Browse,
#[command(about = "Helps opening a MR for the current branch")]
Mr(MrArgs),
#[command(about = "List your mrburns active branches")]
List,
#[command(about = "Set mrburns configuration")]
Config(ConfigArgs),
}
Expand Down
59 changes: 59 additions & 0 deletions src/commands/branches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::{
git::{Git, GitConfig},
utils::get_task_url_config_key,
};

use cliclack::{log, select};

pub fn branches() -> anyhow::Result<()> {
if !Git::is_clean()? {
log::error(
"You have uncommitted changes. Please commit or stash them before switching branches.",
)?;

return Ok(());
}

let branches = Git::all_branches()?;

let current_branch = Git::current_branch()?;

let mrburns_branches: Vec<(String, String)> = branches
.into_iter()
.filter_map(|b| {
let config_key = get_task_url_config_key(&b);
let url = GitConfig::read(&config_key).ok();

if b == current_branch || url.is_none() {
return None;
}

Some((b, url.unwrap()))
})
.collect();

if mrburns_branches.is_empty() {
let _ = log::warning(
"No active mrburns branches found. Start a new task with `mrburns start <task_url>`",
);
} else {
let note_title = format!("Found {} mrburns branches!", mrburns_branches.len());

log::success(note_title)?;

let urls: Vec<(String, String, String)> = mrburns_branches
.iter()
.map(|(branch, url)| (String::from(branch), String::from(url), branch.to_string()))
.collect();

let selected_branch = select("To which task do you want to switch?")
.items(&urls)
.interact()?;

Git::switch(&selected_branch, false)?;

log::info(format!("Switched to branch {}", selected_branch))?;
}

Ok(())
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod branches;
pub mod browse;
pub mod mr;
pub mod start;
Expand Down
6 changes: 3 additions & 3 deletions src/commands/mr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ use cliclack::{

use crate::{
cli::MrArgs,
git::{GitBranch, GitConfig},
git::{Git, GitConfig},
repo_connectors::models::RepoConnector,
task_connectors::task_connector::TaskConnector,
};

pub async fn create_mr(params: &MrArgs) -> anyhow::Result<()> {
let current_branch_name = GitBranch::current()?;
let current_branch_name = Git::current_branch()?;

let task_connector = TaskConnector::from_task_url()?;

let target_branch = params
.base_branch
.to_owned()
.unwrap_or(GitBranch::default()?);
.unwrap_or(Git::default_branch()?);

let confirmed = confirm(format!(
"Creating MR: {} <- {}",
Expand Down
4 changes: 2 additions & 2 deletions src/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cliclack::{

use crate::{
cli::StartArgs,
git::{GitBranch, GitConfig},
git::{Git, GitConfig},
task_connectors::task_connector::TaskConnector,
utils::get_task_url_config_key,
};
Expand All @@ -32,7 +32,7 @@ pub async fn start_task(params: &StartArgs) -> anyhow::Result<()> {

GitConfig::write(&config_key, params.link.as_str())?;

GitBranch::create(&branch_name)?;
Git::switch(&branch_name, true)?;

log::info(format!("Branch {} created!", branch_name))?;
}
Expand Down
100 changes: 74 additions & 26 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,54 @@
use std::process::{Command, Stdio};

pub struct GitConfig {}
use anyhow::bail;

impl GitConfig {
pub fn read(key: &str) -> anyhow::Result<String> {
let git_remote_output = Command::new("git")
.args(["config", "--get", key])
pub struct Git {}

impl Git {
pub fn is_clean() -> anyhow::Result<bool> {
let output = Command::new("git")
.args(["status", "--porcelain"])
.stdout(Stdio::piped())
.output()?;

let key = String::from_utf8(git_remote_output.stdout)?.replace('\n', "");
let files: Vec<String> = String::from_utf8(output.stdout)?
.split('\n')
.filter_map(|s| {
let value = s.trim().to_string();

Ok(key)
}
if value.is_empty() {
return None;
}

pub fn write(key: &str, value: &str) -> anyhow::Result<()> {
let cmd = Command::new("git")
.args(["config", key, value])
.stdout(Stdio::piped())
.status()?;
Some(value)
})
.collect();

if !cmd.success() {
anyhow::bail!("Error writing config key {}", key);
}

Ok(())
Ok(files.len() == 0)
}
}

pub struct GitBranch {}
pub fn switch(name: &str, create_branch: bool) -> anyhow::Result<()> {
let args = if create_branch {
vec!["switch", "-c", name]
} else {
vec!["switch", name]
};

impl GitBranch {
pub fn create(name: &str) -> anyhow::Result<()> {
let output: std::process::Output = Command::new("git")
.args(["switch", "-c", name])
.args(args)
.stdout(Stdio::piped())
.output()?;

let error = String::from_utf8(output.stderr)?;

if error.contains("fatal") {
anyhow::bail!("An error occurred creating branch {}", name);
anyhow::bail!("An error occurred creating branch");
}

Ok(())
}

pub fn default() -> anyhow::Result<String> {
pub fn default_branch() -> anyhow::Result<String> {
let output = Command::new("git")
.args(["symbolic-ref", "refs/remotes/origin/HEAD", "--short"])
.stdout(Stdio::piped())
Expand All @@ -62,7 +64,7 @@ impl GitBranch {
Ok(branch_name)
}

pub fn current() -> anyhow::Result<String> {
pub fn current_branch() -> anyhow::Result<String> {
let output = Command::new("git")
.args(["branch", "--show-current"])
.stdout(Stdio::piped())
Expand All @@ -72,4 +74,50 @@ impl GitBranch {

Ok(branch_name)
}

pub fn all_branches() -> anyhow::Result<Vec<String>> {
let output = Command::new("git")
.args(["branch", "--list"])
.stdout(Stdio::piped())
.output()?;

let branches = String::from_utf8(output.stdout)?
.split('\n')
.map(|s| s.trim().replace("* ", "").to_string())
.collect();

Ok(branches)
}
}

pub struct GitConfig {}

impl GitConfig {
pub fn read(key: &str) -> anyhow::Result<String> {
let git_remote_output = Command::new("git")
.args(["config", "--get", key])
.stdout(Stdio::piped())
.output()?;

let key = String::from_utf8(git_remote_output.stdout)?.replace('\n', "");

if key.is_empty() {
bail!("Config key with no content {}", key);
}

Ok(key)
}

pub fn write(key: &str, value: &str) -> anyhow::Result<()> {
let cmd = Command::new("git")
.args(["config", key, value])
.stdout(Stdio::piped())
.status()?;

if !cmd.success() {
anyhow::bail!("Error writing config key {}", key);
}

Ok(())
}
}
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::Parser;
use cli::{Cli, Commands};
use cliclack::{intro, log, outro};
use commands::{browse, mr, start, wizard::start_config_wizard};
use commands::{branches, browse, mr, start, wizard::start_config_wizard};
use std::process;
use utils::get_latest_version;

Expand Down Expand Up @@ -42,6 +42,7 @@ async fn main() {
Commands::Start(args) => start::start_task(args).await,
Commands::Mr(args) => mr::create_mr(args).await,
Commands::Browse => browse::browse(),
Commands::List => branches::branches(),
Commands::Config(args) => start_config_wizard(args),
};

Expand Down
4 changes: 2 additions & 2 deletions src/repo_connectors/github.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use url::Url;

use crate::{git::GitBranch, task_connectors::models::TaskDetails, utils::get_current_task_url};
use crate::{git::Git, task_connectors::models::TaskDetails, utils::get_current_task_url};

pub struct GithubRepo {}

Expand All @@ -10,7 +10,7 @@ impl GithubRepo {
task_info: &TaskDetails,
target_branch: &str,
) -> anyhow::Result<String> {
let current_branch = GitBranch::current()?;
let current_branch = Git::current_branch()?;

let task_url = get_current_task_url()?;

Expand Down
5 changes: 2 additions & 3 deletions src/repo_connectors/gitlab.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use url::Url;

use crate::{
config::Config, git::GitBranch, task_connectors::models::TaskDetails,
utils::get_current_task_url,
config::Config, git::Git, task_connectors::models::TaskDetails, utils::get_current_task_url,
};

pub struct GitlabRepo {}
Expand All @@ -13,7 +12,7 @@ impl GitlabRepo {
task_info: &TaskDetails,
target_branch: &str,
) -> anyhow::Result<String> {
let current_branch_name = GitBranch::current()?;
let current_branch_name = Git::current_branch()?;

let task_url = get_current_task_url()?;

Expand Down
4 changes: 2 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use reqwest::Client;
use semver::Version;
use serde::{de, Deserialize};

use crate::git::{GitBranch, GitConfig};
use crate::git::{Git, GitConfig};

pub fn get_task_url_config_key(branch_name: &str) -> String {
format!("branch.{}.task-url", branch_name)
}

pub fn get_current_task_url() -> anyhow::Result<String> {
let current_branch_name = GitBranch::current()?;
let current_branch_name = Git::current_branch()?;

let task_url_config_key = get_task_url_config_key(&current_branch_name);

Expand Down

0 comments on commit 6521cf9

Please sign in to comment.