scripts/tools/semver.rs (66 lines of code) (raw):

#!/usr/bin/env -S cargo +nightly -Zscript ---cargo [dependencies] clap = { version = "4", features = ["derive"] } regex = "1" semver = "1" --- // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC use clap::{Parser, Subcommand}; use regex::Regex; use std::error::Error; #[derive(Parser)] #[command(about)] struct Args { #[command(subcommand)] release: Release, } #[derive(Subcommand, Clone)] enum Release { Main { tags: Vec<String> }, FipsV2 { tags: Vec<String> }, FipsV3 { tags: Vec<String> }, } // regex from https://semver.org/ const SEMVER: &str = r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"; fn main() -> Result<(), Box<dyn Error>> { let args = Args::parse(); let latest = match args.release { Release::Main { tags } => get_latest_main(tags)?, Release::FipsV2 { tags } => get_latest_fips(tags, 2)?, Release::FipsV3 { tags } => get_latest_fips(tags, 3)?, }; println!("{latest}"); Ok(()) } fn get_latest_main(tags: Vec<String>) -> Result<String, Box<dyn Error>> { let re = Regex::new(SEMVER)?; let mut tags: Vec<semver::Version> = tags .into_iter() .filter(|t| t.starts_with("v")) .map(|t| String::from(t.strip_prefix("v").expect("prefix must be present"))) .filter(|t| re.is_match(t)) .map(|t| semver::Version::parse(&t).expect("semver parse must not fail")) .collect(); tags.sort(); let latest = tags.pop().ok_or("latest tag not found")?; Ok(format!("v{latest}")) } fn get_latest_fips(tags: Vec<String>, major: u64) -> Result<String, Box<dyn Error>> { const FIPS_TAG_PREFIX: &str = "AWS-LC-FIPS-"; let re = Regex::new(SEMVER)?; let mut tags: Vec<semver::Version> = tags .into_iter() .filter(|t| t.starts_with(FIPS_TAG_PREFIX)) .map(|t| { String::from( t.strip_prefix(FIPS_TAG_PREFIX) .expect("prefix must be present"), ) }) .filter(|t| re.is_match(t)) .map(|t| semver::Version::parse(&t).unwrap()) .filter(|t| t.major == major) .collect(); tags.sort(); let latest = tags.pop().ok_or("latest tag not found")?; Ok(format!("{FIPS_TAG_PREFIX}{latest}")) }