Files
git-issue-commit/src/fetcher/gitlab.rs
7000pctAUTO 4214848922
Some checks failed
CI / test (push) Has been cancelled
CI / release (push) Has been cancelled
Initial commit: git-issue-commit CLI tool
2026-01-29 19:59:21 +00:00

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))
}