use reqwest::header; use serde::{Deserialize, Serialize}; use std::result::Result as StdResult; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error("error from reqwest: {0:#?}")] Reqwest(#[from] reqwest::Error), #[error("bad API token: {0:#?}")] BadAPIToken(#[from] reqwest::header::InvalidHeaderValue), #[error("error parsing/serializing json: {0:#?}")] Json(#[from] serde_json::Error), #[error("tag not found: {0}")] TagNotFound(String), } pub type Result = StdResult; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Author { pub id: i64, pub login: String, pub full_name: String, pub email: String, pub avatar_url: String, pub language: String, pub is_admin: bool, pub last_login: String, pub created: String, pub username: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Release { pub id: i64, pub tag_name: String, pub target_commitish: String, pub name: String, pub body: String, pub url: String, pub tarball_url: String, pub zipball_url: String, pub draft: bool, pub prerelease: bool, pub created_at: String, pub published_at: String, pub author: Author, pub assets: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct CreateRelease { pub body: String, pub draft: bool, pub name: String, pub prerelease: bool, pub tag_name: String, pub target_commitish: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Attachment { pub id: i64, pub name: String, pub size: i64, pub download_count: i64, pub created_at: String, pub uuid: String, pub browser_download_url: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Repo { pub allow_merge_commits: bool, pub allow_rebase: bool, pub allow_rebase_explicit: bool, pub allow_squash_merge: bool, pub archived: bool, pub avatar_url: String, pub clone_url: String, pub created_at: String, pub default_branch: String, pub description: String, pub empty: bool, pub fork: bool, pub forks_count: i64, pub full_name: String, pub has_issues: bool, pub has_pull_requests: bool, pub has_wiki: bool, pub html_url: String, pub id: i64, pub ignore_whitespace_conflicts: bool, pub mirror: bool, pub name: String, pub open_issues_count: i64, pub open_pr_counter: i64, pub original_url: String, pub owner: User, pub permissions: Permissions, pub private: bool, pub release_counter: i64, pub size: i64, pub ssh_url: String, pub stars_count: i64, pub template: bool, pub updated_at: String, pub watchers_count: i64, pub website: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct User { pub avatar_url: String, pub created: String, pub email: String, pub full_name: String, pub id: i64, pub is_admin: bool, pub language: String, pub last_login: String, pub login: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Permissions { pub admin: bool, pub pull: bool, pub push: bool, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Version { pub version: String, } pub struct Client { cli: reqwest::Client, base_url: String, } impl Client { pub fn new(base_url: String, token: String, user_agent: String) -> Result { let mut headers = header::HeaderMap::new(); let auth = format!("token {}", token); let auth = auth.as_str(); headers.insert(header::AUTHORIZATION, header::HeaderValue::from_str(auth)?); let cli = reqwest::Client::builder() .user_agent(user_agent) .default_headers(headers) .build()?; Ok(Self { cli: cli, base_url: base_url, }) } pub async fn version(&self) -> Result { Ok(self .cli .get(&format!("{}/api/v1/version", self.base_url)) .send() .await? .error_for_status()? .json() .await?) } pub async fn get_release_by_tag( &self, owner: String, repo: String, tag: String, ) -> Result { let releases: Vec = self.get_releases(owner, repo).await?; let mut release: Option = None; for rls in releases { if *tag == rls.tag_name { release = Some(rls); } } match release { None => Err(Error::TagNotFound(tag)), Some(release) => Ok(release), } } pub async fn get_repo(&self, owner: String, repo: String) -> Result { Ok(self .cli .get(&format!( "{}/api/v1/repos/{}/{}", self.base_url, owner, repo )) .send() .await? .error_for_status()? .json() .await?) } pub async fn get_releases(&self, owner: String, repo: String) -> Result> { Ok(self .cli .get(&format!( "{}/api/v1/repos/{}/{}/releases", self.base_url, owner, repo )) .send() .await? .error_for_status()? .json() .await?) } pub async fn create_release( &self, owner: String, repo: String, cr: CreateRelease, ) -> Result { Ok(self .cli .post(&format!( "{}/api/v1/repos/{}/{}/releases", self.base_url, owner, repo )) .json(&cr) .send() .await? .error_for_status()? .json() .await?) } }