83 lines
2.4 KiB
Rust
83 lines
2.4 KiB
Rust
use anyhow::{Result, Context};
|
|
use regex::Regex;
|
|
use reqwest::{Client, header::HeaderMap};
|
|
use serde::Deserialize;
|
|
use std::env;
|
|
|
|
#[derive(Deserialize)]
|
|
struct GitLabIssueResponse {
|
|
iid: u64,
|
|
title: String,
|
|
description: Option<String>,
|
|
web_url: String,
|
|
author: Option<GitLabAuthor>,
|
|
labels: Option<Vec<String>>,
|
|
state: Option<String>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct GitLabAuthor {
|
|
username: String,
|
|
}
|
|
|
|
pub async fn fetch_gitlab_issue(url: &str) -> Result<super::IssueContent> {
|
|
let (project_id, number) = parse_gitlab_url(url)?;
|
|
|
|
let client = Client::new();
|
|
let token = env::var("GITLAB_TOKEN").ok();
|
|
|
|
let mut headers = HeaderMap::new();
|
|
if let Some(ref token) = token {
|
|
headers.insert("PRIVATE-TOKEN", token.parse()?);
|
|
}
|
|
|
|
let api_url = env::var("GITLAB_API_URL").unwrap_or_else(|_| "https://gitlab.com/api/v4".to_string());
|
|
let project_encoded = project_id.replace("/", "%2F");
|
|
let issue_url = format!("{}/projects/{}/issues/{}", api_url, project_encoded, number);
|
|
|
|
let response = client
|
|
.get(&issue_url)
|
|
.headers(headers)
|
|
.send()
|
|
.await
|
|
.with_context(|| "Failed to fetch GitLab issue")?;
|
|
|
|
if !response.status().is_success() {
|
|
anyhow::bail!("Failed to fetch GitLab issue: HTTP {}", response.status());
|
|
}
|
|
|
|
let issue: GitLabIssueResponse = response.json().await
|
|
.with_context(|| "Failed to parse GitLab response")?;
|
|
|
|
let labels = issue.labels.unwrap_or_default();
|
|
let author = issue.author.map(|a| a.username).unwrap_or_default();
|
|
|
|
Ok(super::IssueContent {
|
|
title: issue.title,
|
|
body: issue.description.unwrap_or_default(),
|
|
number: issue.iid,
|
|
url: issue.web_url,
|
|
labels,
|
|
author,
|
|
state: issue.state.unwrap_or_default(),
|
|
})
|
|
}
|
|
|
|
fn parse_gitlab_url(url: &str) -> Result<(String, u64)> {
|
|
let re = regex::Regex::new(r"gitlab\.com/([a-zA-Z0-9._/-]+)/-/?(?:issues|merge_requests)/(\d+)")?;
|
|
let caps = re.captures(url)
|
|
.ok_or_else(|| anyhow::anyhow!("Invalid GitLab URL format: {}", url))?;
|
|
|
|
let project_id = caps.get(1)
|
|
.ok_or_else(|| anyhow::anyhow!("Could not extract project ID"))?
|
|
.as_str()
|
|
.to_string();
|
|
|
|
let number = caps.get(2)
|
|
.ok_or_else(|| anyhow::anyhow!("Could not extract issue number"))?
|
|
.as_str()
|
|
.parse::<u64>()?;
|
|
|
|
Ok((project_id, number))
|
|
}
|