//! Gitea API client for deploy key management. use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone)] pub struct GiteaClient { api_url: String, token: String, owner: String, repo: String, } #[derive(Debug, Serialize)] struct CreateKeyRequest<'a> { title: &'a str, key: &'a str, read_only: bool, } #[derive(Debug, Deserialize)] pub struct DeployKey { pub id: u64, #[allow(dead_code)] pub title: String, #[allow(dead_code)] pub key: String, } impl GiteaClient { pub fn new(api_url: &str, token: &str, owner: &str, repo: &str) -> Self { Self { api_url: api_url.trim_end_matches('/').to_string(), token: token.to_string(), owner: owner.to_string(), repo: repo.to_string(), } } /// Create a deploy key, returning its ID. pub fn create_deploy_key(&self, title: &str, public_key: &str) -> Result { let url = format!( "{}/repos/{}/{}/keys", self.api_url, self.owner, self.repo ); let client = reqwest::blocking::Client::new(); let resp = client .post(&url) .header("Authorization", format!("token {}", self.token)) .header("Content-Type", "application/json") .json(&CreateKeyRequest { title, key: public_key, read_only: false, }) .send() .context("Gitea API request failed")?; if !resp.status().is_success() { let status = resp.status(); let body = resp.text().unwrap_or_default(); anyhow::bail!("Gitea API error {}: {}", status, body); } let key: DeployKey = resp.json().context("parse deploy key response")?; Ok(key.id) } /// Delete a deploy key by ID. pub fn delete_deploy_key(&self, key_id: u64) -> Result<()> { let url = format!( "{}/repos/{}/{}/keys/{}", self.api_url, self.owner, self.repo, key_id ); let client = reqwest::blocking::Client::new(); let resp = client .delete(&url) .header("Authorization", format!("token {}", self.token)) .send() .context("Gitea API request failed")?; if !resp.status().is_success() && resp.status().as_u16() != 404 { let status = resp.status(); let body = resp.text().unwrap_or_default(); anyhow::bail!("Gitea API error {}: {}", status, body); } Ok(()) } /// List all deploy keys. #[allow(dead_code)] pub fn list_deploy_keys(&self) -> Result> { let url = format!( "{}/repos/{}/{}/keys", self.api_url, self.owner, self.repo ); let client = reqwest::blocking::Client::new(); let resp = client .get(&url) .header("Authorization", format!("token {}", self.token)) .send() .context("Gitea API request failed")?; if !resp.status().is_success() { let status = resp.status(); let body = resp.text().unwrap_or_default(); anyhow::bail!("Gitea API error {}: {}", status, body); } let keys: Vec = resp.json().context("parse deploy keys response")?; Ok(keys) } }