Initial commit: git-issue-commit CLI tool
This commit is contained in:
96
src/fetcher/github.rs
Normal file
96
src/fetcher/github.rs
Normal 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))
|
||||
}
|
||||
Reference in New Issue
Block a user