use std::process::Command;
use crate::error::{GwError, Result};
use crate::git;
use crate::github;
use crate::output;
use crate::state::RepoType;
pub fn run(verbose: bool) -> Result<()> {
if !git::is_git_repo() {
return Err(GwError::NotAGitRepository);
}
let repo_type = RepoType::detect()?;
let home_branch = repo_type.home_branch();
let current = git::current_branch()?;
println!();
if current == home_branch {
output::warn(&format!("On home branch '{}'. No PR to open.", home_branch));
output::hints(&["gw new feature/your-feature # Start a branch first"]);
return Ok(());
}
if !github::is_gh_available() {
return Err(GwError::Other(
"GitHub CLI (gh) is not available. Install it from https://cli.github.com/".into(),
));
}
let pr = match github::get_pr_for_branch(¤t)? {
Some(pr) => pr,
None => {
output::warn(&format!("No PR found for branch '{}'.", current));
output::hints(&["gh pr create -a \"@me\" -t \"...\" # Create a PR first"]);
return Ok(());
}
};
output::info(&format!("PR: #{} {}", pr.number, pr.title));
open_url(&pr.url, verbose)?;
output::success(&format!("Opened {}", pr.url));
Ok(())
}
pub(crate) fn open_url(url: &str, verbose: bool) -> Result<()> {
let gw_cmd = std::env::var("GW_OPEN_URL_CMD").ok();
let open_cmd = std::env::var("OPEN_URL_CMD").ok();
let program = resolve_open_program(
gw_cmd.as_deref(),
open_cmd.as_deref(),
default_open_program(),
);
if verbose {
output::action(&format!("{} {}", program, url));
}
let status = Command::new(&program)
.arg(url)
.status()
.map_err(|e| GwError::Other(format!("Failed to run open command '{program}': {e}")))?;
if !status.success() {
return Err(GwError::Other(format!(
"Open command '{program}' exited with a non-zero status"
)));
}
Ok(())
}
fn default_open_program() -> &'static str {
if cfg!(target_os = "macos") {
"open"
} else {
"xdg-open"
}
}
fn resolve_open_program(gw_cmd: Option<&str>, open_cmd: Option<&str>, os_default: &str) -> String {
gw_cmd
.filter(|s| !s.is_empty())
.or_else(|| open_cmd.filter(|s| !s.is_empty()))
.unwrap_or(os_default)
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gw_cmd_takes_precedence() {
let program = resolve_open_program(Some("gw-open"), Some("open-url"), "open");
assert_eq!(program, "gw-open");
}
#[test]
fn falls_back_to_open_url_cmd() {
let program = resolve_open_program(None, Some("open-url"), "open");
assert_eq!(program, "open-url");
}
#[test]
fn falls_back_to_os_default() {
let program = resolve_open_program(None, None, "xdg-open");
assert_eq!(program, "xdg-open");
}
#[test]
fn empty_values_are_ignored() {
assert_eq!(
resolve_open_program(Some(""), Some("open-url"), "open"),
"open-url"
);
assert_eq!(resolve_open_program(Some(""), Some(""), "open"), "open");
}
}