git_worktree_cli/
bitbucket_data_center_auth.rs1use std::env;
2
3use crate::error::{Error, Result};
4
5const TOKEN_ENV_VAR: &str = "BITBUCKET_DATA_CENTER_HTTP_ACCESS_TOKEN";
6
7pub struct BitbucketDataCenterAuth;
8
9impl BitbucketDataCenterAuth {
10 pub fn new(_project_key: String, _repo_slug: String, _base_url: String) -> Result<Self> {
11 Ok(BitbucketDataCenterAuth)
12 }
13
14 pub fn get_token(&self) -> Result<String> {
15 env::var(TOKEN_ENV_VAR)
16 .map_err(|_| {
17 Error::auth(format!(
18 "No Bitbucket Data Center access token found. Please set the {} environment variable.\n\
19 Run 'gwt auth bitbucket-data-center setup' for instructions.",
20 TOKEN_ENV_VAR
21 ))
22 })
23 .and_then(|token| {
24 if token.is_empty() {
25 Err(Error::auth(format!(
26 "Bitbucket Data Center access token is empty. Please set the {} environment variable.\n\
27 Run 'gwt auth bitbucket-data-center setup' for instructions.",
28 TOKEN_ENV_VAR
29 )))
30 } else {
31 Ok(token)
32 }
33 })
34 }
35}
36
37fn derive_api_base_url_from_repo_url(repo_url: &str) -> Option<String> {
38 if let Some(captures) = regex::Regex::new(r"https://([^/]+)").ok()?.captures(repo_url) {
42 let domain = captures.get(1)?.as_str();
43 return Some(format!("https://{}", domain));
44 }
45
46 if let Some(captures) = regex::Regex::new(r"git@([^:]+):").ok()?.captures(repo_url) {
48 let domain = captures.get(1)?.as_str();
49 return Some(format!("https://{}", domain));
50 }
51
52 if let Some(captures) = regex::Regex::new(r"ssh://git@([^/]+)").ok()?.captures(repo_url) {
54 let domain = captures.get(1)?.as_str();
55 return Some(format!("https://{}", domain));
56 }
57
58 None
59}
60
61pub fn get_auth_from_config() -> Result<(String, String, String)> {
62 use crate::bitbucket_data_center_api::extract_bitbucket_data_center_info_from_url;
63 use crate::config::GitWorktreeConfig;
64 use crate::github;
65
66 let (_, config) =
67 GitWorktreeConfig::find_config()?.ok_or_else(|| Error::config("No git-worktree-config.jsonc found"))?;
68
69 if config.source_control != "bitbucket-data-center" {
71 return Err(Error::provider(format!(
72 "Repository is not configured for Bitbucket Data Center (sourceControl: {})",
73 config.source_control
74 )));
75 }
76
77 let repo_url = &config.repository_url;
78
79 if let Some((base_url, project_key, repo_slug)) = extract_bitbucket_data_center_info_from_url(repo_url) {
81 return Ok((base_url, project_key, repo_slug));
82 }
83
84 if let Some((owner, repo)) = github::GitHubClient::parse_github_url(repo_url) {
86 if let Some(base_url) = derive_api_base_url_from_repo_url(repo_url) {
88 return Ok((base_url, owner, repo));
89 }
90
91 return Err(Error::provider(format!(
92 "Failed to derive Bitbucket Data Center base URL from: {}",
93 repo_url
94 )));
95 }
96
97 Err(Error::provider(format!("Failed to parse repository URL: {}", repo_url)))
98}
99
100pub fn display_setup_instructions() {
101 println!("Setting up Bitbucket Data Center authentication\n");
102 println!("1. Create an HTTP Access Token in your Bitbucket Data Center instance:");
103 println!(" - Go to your Bitbucket Data Center instance");
104 println!(" - Navigate to your profile settings");
105 println!(" - Go to 'HTTP access tokens' or 'Personal access tokens'");
106 println!(" - Create a new token with repository permissions\n");
107 println!("2. Required permissions for the token:");
108 println!(" - Repository: Read");
109 println!(" - Pull requests: Read\n");
110 println!("3. Copy the generated token\n");
111 println!("4. Set the environment variable:");
112 println!(" export {}=YOUR_TOKEN", TOKEN_ENV_VAR);
113 println!("\nExample usage:");
114 println!(" curl -H \"Authorization: Bearer ${}\" \\", TOKEN_ENV_VAR);
115 println!(" \"https://git.acmeorg.com/rest/api/1.0/projects/PROJECT/repos/REPO/pull-requests\"");
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn test_bitbucket_data_center_auth_creation() {
124 let auth = BitbucketDataCenterAuth::new(
125 "PROJECT".to_string(),
126 "repository".to_string(),
127 "https://git.acmeorg.com".to_string(),
128 );
129 assert!(auth.is_ok());
130 }
131
132 #[test]
133 fn test_auth_structure() {
134 let auth = BitbucketDataCenterAuth::new(
135 "PROJ".to_string(),
136 "repo".to_string(),
137 "https://git.example.com".to_string(),
138 );
139 assert!(auth.is_ok());
140 }
141}