mesa/common/
gitea.rs

1#![allow(dead_code, unused_imports)] // TODO: to avoid compiler from complaining about unused methods
2
3pub mod http_client {
4
5    use std::str::FromStr;
6
7    use crate::{config, error::Error};
8    use serde_json::Value;
9
10    /// Get all refs for a repository
11    /// Used when getting repo details
12    pub async fn get_all_refs_from_repo_url(
13        gitea_base_url: &str,
14        gitea_token: &str,
15        repo_url: &str,
16        shasta_root_cert: &[u8],
17    ) -> Result<Vec<Value>, crate::error::Error> {
18        let gitea_internal_base_url = "https://api-gw-service-nmn.local/vcs/cray/";
19        // let gitea_external_base_url = "https://api.cmn.alps.cscs.ch/vcs/";
20
21        let repo_name = repo_url
22            .trim_start_matches(gitea_internal_base_url)
23            .trim_end_matches(".git");
24
25        get_all_refs(gitea_base_url, gitea_token, repo_name, shasta_root_cert).await
26    }
27
28    /// Get all refs for a repository
29    /// Used when getting repo details
30    pub async fn get_all_refs(
31        gitea_base_url: &str,
32        gitea_token: &str,
33        repo_name: &str,
34        shasta_root_cert: &[u8],
35    ) -> Result<Vec<Value>, Error> {
36        let client_builder = reqwest::Client::builder()
37            .add_root_certificate(reqwest::Certificate::from_pem(shasta_root_cert).unwrap());
38
39        // Build client
40        let client = if std::env::var("SOCKS5").is_ok() {
41            // socks5 proxy
42            let socks5proxy = reqwest::Proxy::all(std::env::var("SOCKS5").unwrap()).unwrap();
43
44            // rest client to authenticate
45            client_builder.proxy(socks5proxy).build().unwrap()
46        } else {
47            client_builder.build().unwrap()
48        };
49
50        let api_url = format!(
51            "{}/api/v1/repos/cray/{}/git/refs",
52            gitea_base_url, repo_name
53        );
54
55        log::debug!("Get refs in gitea using through API call: {}", api_url);
56
57        let response = client
58            .get(api_url)
59            .header("Authorization", format!("token {}", gitea_token))
60            .send()
61            .await
62            .map_err(|error| Error::NetError(error))?;
63        // .error_for_status()?
64        // .json::<Vec<Value>>()
65        // .await
66
67        if response.status().is_success() {
68            response.json().await.map_err(|e| Error::NetError(e))
69        } else {
70            Err(Error::Message(response.text().await?))
71        }
72        /*
73        match resp_rslt {
74            Ok(resp) => Ok(resp),
75            Err(error) => Err(Error::NetError(error)),
76        } */
77    }
78
79    /// Get most commit id (sha) pointed by a branch
80    pub async fn get_commit_pointed_by_branch(
81        gitea_base_url: &str,
82        gitea_token: &str,
83        shasta_root_cert: &[u8],
84        repo_url: &str,
85        branch_name: &str,
86    ) -> Result<String, crate::error::Error> {
87        let all_ref_vec =
88            get_all_refs_from_repo_url(gitea_base_url, gitea_token, repo_url, shasta_root_cert)
89                .await?;
90
91        let ref_details_opt = all_ref_vec.into_iter().find(|ref_details| {
92            ref_details["ref"].as_str().unwrap() == format!("refs/heads/{}", branch_name)
93        });
94
95        match ref_details_opt {
96            Some(ref_details) => Ok(ref_details["object"]["sha"].as_str().unwrap().to_string()),
97            None => Err(Error::Message("SHA for branch not found".to_string())),
98        }
99    }
100
101    /// Returns the commit id (sha) related to a tag name
102    /// Used to translate CFS configuration layer tag name into commit id values when processing
103    /// SAT files
104    pub async fn get_tag_details(
105        repo_url: &str,
106        tag: &str,
107        gitea_token: &str,
108        shasta_root_cert: &[u8],
109        site_name: &str,
110    ) -> Result<Value, reqwest::Error> {
111        let gitea_internal_base_url = "https://api-gw-service-nmn.local/vcs/";
112        // let gitea_external_base_url = "https://api.cmn.alps.cscs.ch/vcs/";
113        let gitea_external_base_url = format!("https://api.cmn.{}.cscs.ch/vcs/", site_name);
114
115        let gitea_api_base_url = gitea_internal_base_url.to_owned() + "api/v1";
116
117        let repo_name = repo_url
118            .trim_start_matches(gitea_internal_base_url)
119            .trim_end_matches(".git");
120        let repo_name = repo_name
121            .trim_start_matches(&gitea_external_base_url)
122            .trim_end_matches(".git");
123
124        /* log::info!("repo_url: {}", repo_url);
125        log::info!("gitea_base_url: {}", gitea_internal_base_url);
126        log::info!("repo_name: {}", repo_name); */
127
128        let client;
129
130        let client_builder = reqwest::Client::builder()
131            .add_root_certificate(reqwest::Certificate::from_pem(shasta_root_cert)?);
132
133        // Build client
134        if std::env::var("SOCKS5").is_ok() {
135            // socks5 proxy
136            let socks5proxy = reqwest::Proxy::all(std::env::var("SOCKS5").unwrap())?;
137
138            // rest client to authenticate
139            client = client_builder.proxy(socks5proxy).build()?;
140        } else {
141            client = client_builder.build()?;
142        }
143
144        let api_url = format!("{}/repos/{}/tags/{}", gitea_api_base_url, repo_name, tag);
145
146        log::debug!("Request to {}", api_url);
147
148        client
149            .get(api_url)
150            .header("Authorization", format!("token {}", gitea_token))
151            .send()
152            .await?
153            .json()
154            .await
155    }
156
157    /// Returns the commit id (sha) related to a tag name
158    /// Used to translate CFS configuration layer tag name into commit id values when processing
159    /// SAT files
160    pub async fn get_commit_from_tag(
161        gitea_api_tag_url: &str,
162        tag: &str,
163        gitea_token: &str,
164        shasta_root_cert: &[u8],
165        site_name: &str,
166    ) -> Result<Value, Error> {
167        let gitea_repo_url_prefix = format!(
168            "https://vcs.cmn.{}.cscs.ch/vcs/api/v1/repos/cray/",
169            site_name
170        );
171
172        let repo_name: &str = gitea_api_tag_url
173            .trim_start_matches(&gitea_repo_url_prefix)
174            .split('/')
175            .next()
176            .unwrap();
177
178        let api_url = format!("{}{}/tags/{}", gitea_repo_url_prefix, repo_name, tag);
179
180        let client;
181
182        let client_builder = reqwest::Client::builder()
183            .add_root_certificate(reqwest::Certificate::from_pem(shasta_root_cert)?);
184
185        // Build client
186        if std::env::var("SOCKS5").is_ok() {
187            // socks5 proxy
188            let socks5proxy = reqwest::Proxy::all(std::env::var("SOCKS5").unwrap())?;
189
190            // rest client to authenticate
191            client = client_builder.proxy(socks5proxy).build()?;
192        } else {
193            client = client_builder.build()?;
194        }
195
196        log::debug!("Request to {}", api_url);
197
198        let response_rslt = client
199            .get(api_url.clone())
200            .header("Authorization", format!("token {}", gitea_token))
201            .send()
202            .await;
203
204        match response_rslt {
205            Ok(response) => Ok(response.json::<Value>().await?),
206            Err(error) => Err(Error::NetError(error)),
207        }
208    }
209
210    // Get commit details.
211    // NOTE: repo_name value must not contain the group (eg in CSSC gitlab we have
212    // alps/csm-config/template-management and in gitea is vcs/api/v1/repos/template-management
213    pub async fn get_commit_details_from_external_url(
214        // repo_url: &str,
215        repo_name: &str,
216        commitid: &str,
217        gitea_token: &str,
218        shasta_root_cert: &[u8],
219        site_name: &str,
220    ) -> Result<Value, crate::error::Error> {
221        // let gitea_external_base_url = "https://api.cmn.alps.cscs.ch/vcs/";
222        let gitea_external_base_url = format!("https://api.cmn.{}.cscs.ch/vcs/", site_name);
223
224        /* let repo_name = repo_url
225        .trim_end_matches(".git")
226        .trim_start_matches(gitea_external_base_url); */
227
228        /* if repo_name.ne(repo_url) {
229            crate::error::Error::Message(
230                "repo url provided does not match gitea internal URL".to_string(),
231            );
232        } */
233
234        get_commit_details(
235            &gitea_external_base_url,
236            repo_name,
237            commitid,
238            gitea_token,
239            shasta_root_cert,
240        )
241        .await
242    }
243
244    pub async fn get_commit_details(
245        gitea_base_url: &str,
246        repo_name: &str,
247        commitid: &str,
248        gitea_token: &str,
249        shasta_root_cert: &[u8],
250    ) -> Result<Value, crate::error::Error> {
251        let client;
252
253        let client_builder = reqwest::Client::builder()
254            .add_root_certificate(reqwest::Certificate::from_pem(shasta_root_cert)?);
255
256        // Build client
257        if std::env::var("SOCKS5").is_ok() {
258            // socks5 proxy
259            let socks5proxy = reqwest::Proxy::all(std::env::var("SOCKS5").unwrap())?;
260
261            // rest client to authenticate
262            client = client_builder.proxy(socks5proxy).build()?;
263        } else {
264            client = client_builder.build()?;
265        }
266
267        let api_url = format!(
268            "{}api/v1/repos/{}/git/commits/{}",
269            gitea_base_url, repo_name, commitid
270        );
271
272        log::info!("url to get commit details: {}", api_url);
273
274        let response = client
275            .get(api_url)
276            .header("Authorization", format!("token {}", gitea_token))
277            .send()
278            .await?;
279
280        if response.status().is_success() {
281            // Make sure we return a vec if user requesting a single value
282            response
283                .json()
284                .await
285                .map_err(|error| Error::NetError(error))
286        } else {
287            let payload = response.text().await.unwrap();
288            Err(Error::CsmError(serde_json::json!({ "message": payload })))
289        }
290    }
291
292    pub async fn get_last_commit_from_repo_name(
293        gitea_api_base_url: &str,
294        repo_name: &str,
295        gitea_token: &str,
296        shasta_root_cert: &[u8],
297    ) -> core::result::Result<Value, reqwest::Error> {
298        let repo_url = gitea_api_base_url.to_owned() + "/api/v1/repos" + repo_name + "/commits";
299
300        let client;
301
302        let client_builder = reqwest::Client::builder()
303            .add_root_certificate(reqwest::Certificate::from_pem(shasta_root_cert)?);
304
305        // Build client
306        if std::env::var("SOCKS5").is_ok() {
307            // socks5 proxy
308            let socks5proxy = reqwest::Proxy::all(std::env::var("SOCKS5").unwrap())?;
309
310            // rest client to authenticate
311            client = client_builder.proxy(socks5proxy).build()?;
312        } else {
313            client = client_builder.build()?;
314        }
315
316        let mut resp: Vec<Value> = client
317            .get(repo_url)
318            .header("Authorization", format!("token {}", gitea_token))
319            .send()
320            .await?
321            .error_for_status()?
322            .json()
323            .await?;
324
325        resp.sort_by(|a, b| {
326            a["commit"]["committer"]["date"]
327                .to_string()
328                .cmp(&b["commit"]["committer"]["date"].to_string())
329        });
330
331        Ok(resp.last().unwrap().clone())
332    }
333
334    pub async fn get_last_commit_from_url(
335        gitea_api_base_url: &str,
336        repo_url: &str,
337        gitea_token: &str,
338        shasta_root_cert: &[u8],
339    ) -> core::result::Result<Value, reqwest::Error> {
340        let repo_name = repo_url
341            .trim_start_matches("https://api-gw-service-nmn.local/vcs/")
342            .trim_end_matches(".git");
343
344        get_last_commit_from_repo_name(gitea_api_base_url, repo_name, gitea_token, shasta_root_cert)
345            .await
346    }
347}