bb_cli/commands/
browse.rs1use crate::error::Result;
2use crate::output::{self, Format};
3use crate::repo::{self, RepoSlug};
4
5#[derive(Debug, Clone, Copy)]
6pub enum BrowseTarget {
7 Pr(u64),
8 Branches,
9}
10
11pub fn url_for(slug: &RepoSlug, target: Option<&BrowseTarget>) -> String {
12 let base = slug.browse_url();
13 match target {
14 Some(BrowseTarget::Pr(id)) => format!("{base}/pull-requests/{id}"),
15 Some(BrowseTarget::Branches) => format!("{base}/branches"),
16 None => base,
17 }
18}
19
20pub fn browse(
21 repo_arg: Option<&str>,
22 target: Option<BrowseTarget>,
23 print_only: bool,
24 format: Format,
25) -> Result<()> {
26 let slug = repo::resolve(repo_arg)?;
28 let url = url_for(&slug, target.as_ref());
29
30 if format.is_json() {
31 return output::print_json(&serde_json::json!({ "url": url }));
32 }
33
34 println!("{url}");
35
36 if !print_only {
37 if let Err(err) = open::that_detached(&url) {
39 output::warn(&format!("cannot open a browser: {err}"));
40 }
41 }
42
43 Ok(())
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 fn slug() -> RepoSlug {
51 RepoSlug {
52 workspace: "acme".into(),
53 repo: "widgets".into(),
54 }
55 }
56
57 #[test]
58 fn repo_url_has_no_suffix() {
59 assert_eq!(url_for(&slug(), None), "https://bitbucket.org/acme/widgets");
60 }
61
62 #[test]
63 fn pr_url_includes_the_id() {
64 assert_eq!(
65 url_for(&slug(), Some(&BrowseTarget::Pr(7))),
66 "https://bitbucket.org/acme/widgets/pull-requests/7"
67 );
68 }
69
70 #[test]
71 fn branches_url() {
72 assert!(url_for(&slug(), Some(&BrowseTarget::Branches)).ends_with("/branches"));
73 }
74
75 #[test]
82 fn dash_prefixed_workspace_produces_a_well_formed_url() {
83 let slug = RepoSlug {
84 workspace: "-rf".into(),
85 repo: "widgets".into(),
86 };
87 let url = url_for(&slug, None);
88 assert_eq!(url, "https://bitbucket.org/-rf/widgets");
89 assert!(url.starts_with("https://"));
90 }
91}