Initial commit: git-issue-commit CLI tool
This commit is contained in:
82
src/fetcher/gitlab.rs
Normal file
82
src/fetcher/gitlab.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
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))
|
||||
}
|
||||
Reference in New Issue
Block a user