1#![allow(clippy::print_stdout, clippy::print_stderr)]
7
8use crate::cli::BrowseCommand;
9use crate::repository::{detect_remote, parse_repo_spec};
10use anyhow::Context;
11
12pub fn run(cmd: BrowseCommand, hostname: Option<&str>) -> anyhow::Result<()> {
18 let spec = match cmd.repo.as_deref() {
19 Some(s) => parse_repo_spec(s).context("invalid repository spec")?,
20 None => detect_remote().ok_or_else(|| {
21 anyhow::anyhow!(
22 "could not detect repository from current directory; specify OWNER/REPO with --repo"
23 )
24 })?,
25 };
26
27 let host = hostname.unwrap_or("github.com");
28 let base_url = format!("https://{host}/{}/{}", spec.owner, spec.repo);
29
30 let url = if let Some(issue) = cmd.issue {
31 format!("{base_url}/issues/{issue}")
32 } else if let Some(pr) = cmd.pr {
33 format!("{base_url}/pull/{pr}")
34 } else if let Some(branch) = cmd.branch {
35 format!("{base_url}/tree/{branch}")
36 } else if let Some(commit) = cmd.commit {
37 format!("{base_url}/commit/{commit}")
38 } else if cmd.projects {
39 format!("{base_url}/projects")
40 } else if cmd.wiki {
41 format!("{base_url}/wiki")
42 } else if cmd.settings {
43 format!("{base_url}/settings")
44 } else {
45 base_url
46 };
47
48 open_in_browser(&url);
49 println!("Opening {url}");
50 Ok(())
51}
52
53pub fn open_in_browser(url: &str) {
55 #[cfg(target_os = "linux")]
56 {
57 let _ = std::process::Command::new("xdg-open").arg(url).spawn();
58 }
59 #[cfg(target_os = "macos")]
60 {
61 let _ = std::process::Command::new("open").arg(url).spawn();
62 }
63 #[cfg(target_os = "windows")]
64 {
65 let _ = std::process::Command::new("cmd")
66 .args(["/c", "start", url])
67 .spawn();
68 }
69 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
70 {
71 println!("Open {url} in your browser");
72 }
73}
74
75#[cfg(test)]
76#[allow(clippy::expect_used)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn open_in_browser_does_not_panic() {
82 open_in_browser("https://github.com/octocat/hello-world");
83 }
84}