use miette::IntoDiagnostic;
use crate::{fg_magenta, http_client, ok, SCRIPT_MOD_DEBUG};
mod constants {
pub const TAG_NAME: &str = "tag_name";
pub const VERSION_PREFIX: &str = "v";
}
mod urls {
pub const REPO_LATEST_RELEASE: &str =
"https://api.github.com/repos/{org}/{repo}/releases/latest";
}
pub async fn try_get_latest_release_tag_from_github(
org: &str,
repo: &str,
) -> miette::Result<String> {
let url = urls::REPO_LATEST_RELEASE
.replace("{org}", org)
.replace("{repo}", repo);
SCRIPT_MOD_DEBUG.then(|| {
tracing::debug!(
message = "Fetching latest release tag from GitHub",
url = %fg_magenta(&url)
);
});
let client = http_client::create_client_with_user_agent(None)?;
let response = client.get(url).send().await.into_diagnostic()?;
let response = response.error_for_status().into_diagnostic()?; let response: serde_json::Value = response.json().await.into_diagnostic()?;
let tag_name = match response[constants::TAG_NAME].as_str() {
Some(tag_name) => tag_name.trim_start_matches(constants::VERSION_PREFIX),
None => miette::bail!("Failed to get tag name from JSON: {:?}", response),
};
ok!(tag_name.to_owned())
}
#[cfg(test)]
mod tests_github_api {
use std::time::Duration;
use tokio::time::timeout;
use super::*;
use crate::{return_if_not_interactive_terminal, TTYResult};
const TIMEOUT: Duration = Duration::from_secs(1);
#[tokio::test]
async fn test_get_latest_tag_from_github() {
return_if_not_interactive_terminal!();
let org = "cloudflare";
let repo = "cfssl";
match timeout(TIMEOUT, try_get_latest_release_tag_from_github(org, repo)).await {
Ok(Ok(tag)) => {
assert!(!tag.is_empty());
println!("Latest tag: {}", fg_magenta(&tag));
}
Ok(Err(err)) => {
panic!("Error: {err:?}");
}
Err(_) => {
println!("Timeout");
}
}
}
}