lean_ctx/core/providers/
config.rs1#[derive(Clone)]
2pub struct GitLabConfig {
3 pub host: String,
4 pub token: String,
5 pub project_path: Option<String>,
6}
7
8impl std::fmt::Debug for GitLabConfig {
9 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
10 f.debug_struct("GitLabConfig")
11 .field("host", &self.host)
12 .field("token", &"[REDACTED]")
13 .field("project_path", &self.project_path)
14 .finish()
15 }
16}
17
18impl GitLabConfig {
19 pub fn from_session() -> Result<Self, String> {
20 super::selected_gitlab::config().map_or_else(Self::from_env, Ok)
21 }
22
23 pub fn from_env() -> Result<Self, String> {
24 let token = super::credentials::var("LEAN_CTX_GITLAB_TOKEN")
25 .or_else(|_| super::credentials::var("GITLAB_TOKEN"))
26 .or_else(|_| super::credentials::var("CI_JOB_TOKEN"))
27 .map_err(|_| {
28 "No GitLab token found. Set GITLAB_TOKEN or LEAN_CTX_GITLAB_TOKEN.".to_string()
29 })?;
30
31 let host = super::credentials::var("GITLAB_HOST")
32 .or_else(|_| super::credentials::var("CI_SERVER_HOST"))
33 .unwrap_or_else(|_| "gitlab.com".to_string());
34
35 let project_path = super::credentials::var("CI_PROJECT_PATH")
36 .ok()
37 .or_else(|| detect_project_from_git_remote(&host));
38
39 Ok(Self {
40 host,
41 token,
42 project_path,
43 })
44 }
45
46 pub fn api_url(&self, endpoint: &str) -> String {
47 #[cfg(any(test, feature = "test-support"))]
51 if crate::core::data_dir::sandboxed()
52 && let Some(fixture) = self.host.strip_prefix("http://127.0.0.1:")
53 {
54 return format!("http://127.0.0.1:{fixture}/api/v4{endpoint}");
55 }
56 format!("https://{}/api/v4{}", self.host, endpoint)
57 }
58}
59
60fn detect_project_from_git_remote(host: &str) -> Option<String> {
61 let output = std::process::Command::new("git")
62 .args(["remote", "get-url", "origin"])
63 .output()
64 .ok()?;
65 if !output.status.success() {
66 return None;
67 }
68 let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
69
70 if let Some(rest) = url.strip_prefix(&format!("git@{host}:")) {
72 return Some(rest.trim_end_matches(".git").to_string());
73 }
74 if let Some(rest) = url.strip_prefix(&format!("https://{host}/")) {
76 return Some(rest.trim_end_matches(".git").to_string());
77 }
78 None
79}