use anyhow::{bail, Result};
use reqwest::Client;
use semver::Version;
use serde::Deserialize;
use crate::{download_binary, OneConfig, ReleaseDep, RepoProvider};
#[allow(unused)]
#[derive(Debug, Deserialize)]
pub struct GiteeRelease {
id: u64,
tag_name: String,
name: String,
body: String,
draft: Option<bool>,
prerelease: bool,
created_at: Option<String>,
published_at: Option<String>,
assets: Vec<GiteeAsset>,
}
#[derive(Debug, Deserialize)]
pub struct GiteeAsset {
name: String,
browser_download_url: String,
}
pub async fn gitee_get_release(config: OneConfig) -> Result<ReleaseDep> {
let client = Client::new();
let url_info = &config.url_info;
let mut page = 1;
let per_page = 20; let mut total_pages: Option<u32> = None;
loop {
let url = format!(
"https://gitee.com/api/v5/repos/{}/{}/releases?page={}&per_page={}&direction=desc",
url_info.owner, url_info.repo, page, per_page
);
println!("Fetching releases from: {url}");
if let Some(total) = total_pages {
println!("Processing page {page}/{total}");
} else {
println!("Processing page {page}");
}
let response = client.get(&url).send().await?;
if !response.status().is_success() {
bail!("Failed to fetch releases from Gitee: {}", response.status());
}
if total_pages.is_none() {
if let Some(total_page_header) = response.headers().get("total_page") {
if let Ok(total_page_str) = total_page_header.to_str() {
if let Ok(pages) = total_page_str.parse::<u32>() {
total_pages = Some(pages);
println!("Total pages available: {pages}");
}
}
}
}
let releases: Vec<GiteeRelease> = response.json().await?;
if releases.is_empty() {
bail!("No releases found for {}/{}", url_info.owner, url_info.repo);
}
let releases_len = releases.len();
for release in releases {
if release.draft.unwrap_or(false) || release.prerelease {
continue;
}
let version_str = if release.tag_name.contains("-v") {
release
.tag_name
.split("-v")
.last()
.unwrap_or(&release.tag_name)
} else if release.tag_name.starts_with('v') {
&release.tag_name[1..]
} else {
&release.tag_name
};
println!(
"Parsing version from tag: {} -> {version_str}",
release.tag_name
);
if let Ok(release_version) = Version::parse(version_str) {
if config.version.matches(&release_version) {
println!(
"Found compatible version: {release_version} (requested: {})",
config.version
);
for asset in &release.assets {
if asset.name.contains(&config.package) {
println!("Found matching asset: {}", asset.name);
let download_dir =
config.download_dir.as_ref().map(|p| p.to_str().unwrap());
let binary_path = download_binary(
&client,
&asset.browser_download_url,
&asset.name,
download_dir,
RepoProvider::Gitee,
)
.await?;
println!("Successfully found and downloaded release on page {page}");
return Ok(ReleaseDep {
name: config.package.clone(),
version: release_version,
binary: binary_path,
});
}
}
println!("No matching binary found for release {}", release.tag_name);
}
}
}
if let Some(total) = total_pages {
if page >= total {
println!("Reached last page ({page}/{total})");
break;
}
} else {
if releases_len < per_page {
break;
}
}
page += 1;
}
bail!(
"No compatible release found for package {} with version {}",
config.package,
config.version
);
}