release-checker/src/dockerhub.rs
Aode (lion) 8f37beb0b1
All checks were successful
continuous-integration/drone/push Build is passing
Add dockerhub pagination up to 100 tags
2022-01-28 09:55:51 -06:00

96 lines
2.6 KiB
Rust

use crate::{
revision::Revision,
version::{LatestOrSemver, Version},
BuildDirective,
};
#[derive(Debug)]
enum DockerError {
NoTag,
}
#[derive(Debug, serde::Deserialize)]
struct TagResult {
name: String,
}
#[derive(Debug, serde::Deserialize)]
struct TagsResponse {
count: usize,
next: String,
results: Vec<TagResult>,
}
impl std::fmt::Display for DockerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoTag => write!(f, "No tag found for query"),
}
}
}
impl std::error::Error for DockerError {}
const CHECK_MAX: usize = 100;
#[tracing::instrument]
pub(crate) async fn check_dockerhub_image(
namespace: String,
repository: String,
regex: String,
prefix: Option<String>,
previous_revision: &Revision,
) -> color_eyre::eyre::Result<BuildDirective> {
let regex = regex::Regex::new(&regex)?;
let client = reqwest::Client::builder()
.user_agent("release-checker (+https://git.asonix.dog/asonix/release-checker)")
.build()?;
let images_url = format!("https://registry.hub.docker.com/v2/repositories/{}/{}/tags?currently_tagged=true,ordering=last_updated,status=active", namespace, repository);
let mut next_url = Some(images_url);
let mut checked = 0;
while let Some(next) = next_url {
let tags: TagsResponse = client.get(&next).send().await?.json().await?;
checked += tags.results.len();
next_url = if checked < tags.count.min(CHECK_MAX) {
Some(tags.next)
} else {
None
};
let opt = tags
.results
.into_iter()
.filter_map(|result| {
if let Some(matched) = regex.find(&result.name) {
if matched.as_str() == result.name {
let trimmed = if let Some(prefix) = prefix.as_deref() {
result.name.trim_start_matches(prefix)
} else {
&result.name
};
return Some(Version::parse_from(trimmed));
}
}
None
})
.latest_or_semver(None);
if let Some(version) = opt {
// Bail if newest published version is the same as our most recent build
if version <= previous_revision.version {
return Ok(BuildDirective::ShouldIgnore);
}
return Ok(BuildDirective::ShouldBuild(Some(version)));
}
}
Err(DockerError::NoTag.into())
}