Initial commit: git-issue-commit CLI tool
Some checks failed
CI / test (push) Has been cancelled
CI / release (push) Has been cancelled

This commit is contained in:
2026-01-29 19:59:20 +00:00
parent 53d7ac7593
commit e4e75505b7

96
src/fetcher/github.rs Normal file
View File

@@ -0,0 +1,96 @@
use anyhow::{Result, Context};
use regex::Regex;
use reqwest::{Client, header::HeaderMap};
use serde::Deserialize;
use std::env;
#[derive(Deserialize)]
struct GitHubIssueResponse {
number: u64,
title: String,
body: Option<String>,
html_url: String,
user: Option<GitHubUser>,
labels: Option<Vec<GitHubLabel>>,
state: Option<String>,
}
#[derive(Deserialize)]
struct GitHubUser {
login: String,
}
#[derive(Deserialize)]
struct GitHubLabel {
name: String,
}
pub async fn fetch_github_issue(url: &str) -> Result<super::IssueContent> {
let (owner, repo, number) = parse_github_url(url)?;
let client = Client::new();
let token = env::var("GITHUB_TOKEN").ok();
let mut headers = HeaderMap::new();
if let Some(ref token) = token {
headers.insert("Authorization", format!("Bearer {}", token).parse()?);
}
let api_url = env::var("GITHUB_API_URL").unwrap_or_else(|_| "https://api.github.com".to_string());
let issue_url = format!("{}/repos/{}/{}/issues/{}", api_url, owner, repo, number);
let response = client
.get(&issue_url)
.headers(headers)
.send()
.await
.with_context(|| "Failed to fetch GitHub issue")?;
if !response.status().is_success() {
anyhow::bail!("Failed to fetch GitHub issue: HTTP {}", response.status());
}
let issue: GitHubIssueResponse = response.json().await
.with_context(|| "Failed to parse GitHub response")?;
let labels = issue.labels.unwrap_or_default()
.into_iter()
.map(|l| l.name)
.collect();
let author = issue.user.map(|u| u.login).unwrap_or_default();
Ok(super::IssueContent {
title: issue.title,
body: issue.body.unwrap_or_default(),
number: issue.number,
url: issue.html_url,
labels,
author,
state: issue.state.unwrap_or_default(),
})
}
fn parse_github_url(url: &str) -> Result<(String, String, u64)> {
let re = regex::Regex::new(r"github\.com/([a-zA-Z0-9._-]+)/([a-zA-Z0-9._-]+)(?:\.git)?/(?:issues|pull)/(\d+)")?;
let caps = re.captures(url)
.ok_or_else(|| anyhow::anyhow!("Invalid GitHub URL format: {}", url))?;
let owner = caps.get(1)
.ok_or_else(|| anyhow::anyhow!("Could not extract owner"))?
.as_str()
.to_string();
let repo = caps.get(2)
.ok_or_else(|| anyhow::anyhow!("Could not extract repository"))?
.as_str()
.trim_end_matches(".git")
.to_string();
let number = caps.get(3)
.ok_or_else(|| anyhow::anyhow!("Could not extract issue number"))?
.as_str()
.parse::<u64>()?;
Ok((owner, repo, number))
}