From d649732acd58fd6eeb1b61dee0932192aadf3ee7 Mon Sep 17 00:00:00 2001 From: Mubelotix Date: Mon, 25 Aug 2025 15:16:26 +0200 Subject: [PATCH] Do so that meilisearch versions get downloaded --- crates/xtask/src/test/mod.rs | 3 +- crates/xtask/src/test/versions.rs | 115 ++++++++++++++++++++++++++++++ crates/xtask/src/test/workload.rs | 41 +++++++++-- 3 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 crates/xtask/src/test/versions.rs diff --git a/crates/xtask/src/test/mod.rs b/crates/xtask/src/test/mod.rs index 3ecd2ce1c..94bd88ecb 100644 --- a/crates/xtask/src/test/mod.rs +++ b/crates/xtask/src/test/mod.rs @@ -5,6 +5,7 @@ use anyhow::{bail, Context}; use cargo_metadata::semver::Version; use clap::Parser; +mod versions; mod workload; pub use workload::TestWorkload; @@ -51,7 +52,7 @@ async fn run_inner(args: TestDeriveArgs) -> anyhow::Result<()> { ) .with_context(|| format!("error parsing {} as JSON", workload_file.display()))?; - let Workload::Test(workload) = workload else { + let Workload::Test(mut workload) = workload else { bail!("workload file {} is not a test workload", workload_file.display()); }; diff --git a/crates/xtask/src/test/versions.rs b/crates/xtask/src/test/versions.rs new file mode 100644 index 000000000..78c7b135e --- /dev/null +++ b/crates/xtask/src/test/versions.rs @@ -0,0 +1,115 @@ +use std::collections::BTreeMap; + +use crate::common::assets::{Asset, AssetFormat}; +use anyhow::Context; +use cargo_metadata::semver::Version; +use serde::Deserialize; + +async fn get_sha256(version: &Version, asset_name: &str) -> anyhow::Result { + #[derive(Deserialize)] + struct GithubReleaseAsset { + name: String, + digest: String, + } + + #[derive(Deserialize)] + struct GithubRelease { + assets: Vec, + } + + let url = + format!("https://api.github.com/repos/meilisearch/meilisearch/releases/tags/v{version}"); + let data: GithubRelease = reqwest::get(url).await?.json().await?; + + let digest = data + .assets + .into_iter() + .find(|asset| asset.name.as_str() == asset_name) + .with_context(|| format!("asset {asset_name} not found in release v{version}"))? + .digest; + + let sha256 = + digest.strip_prefix("sha256:").map(|s| s.to_string()).context("invalid sha256 format")?; + + Ok(sha256) +} + +async fn add_asset(assets: &mut BTreeMap, version: &Version) -> anyhow::Result<()> { + let arch; + + // linux-aarch64 + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] + { + arch = "linux-aarch64"; + } + + // linux-amd64 + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + { + arch = "linux-amd64"; + } + + // macos-amd64 + #[cfg(all(target_os = "macos", target_arch = "x86_64"))] + { + arch = "macos-amd64"; + } + + // macos-apple-silicon + #[cfg(all(target_os = "macos", target_arch = "aarch64"))] + { + arch = "macos-apple-silicon"; + } + + // windows-amd64 + #[cfg(all(target_os = "windows", target_arch = "x86_64"))] + { + arch = "windows-amd64"; + } + + if arch.is_empty() { + anyhow::bail!("unsupported platform"); + } + + let local_filename = format!("meilisearch-{version}-{arch}"); + if assets.contains_key(&local_filename) { + return Ok(()); + } + + let filename = format!("meilisearch-{arch}"); + + // Try to get the sha256 but it may fail if Github is rate limiting us + let sha256 = match get_sha256(version, &filename).await { + Ok(sha256) => Some(sha256), + Err(err) => { + eprintln!("⚠️ Warning: could not get sha256 from GitHub: {err}. Proceeding without integrity check."); + None + } + }; + + let url = format!( + "https://github.com/meilisearch/meilisearch/releases/download/v{version}/{filename}" + ); + + let asset = Asset { + local_location: Some(local_filename.clone()), + remote_location: Some(url), + format: AssetFormat::Raw, + sha256, + }; + + assets.insert(local_filename, asset); + + Ok(()) +} + +pub async fn expand_assets_with_versions( + assets: &mut BTreeMap, + versions: &[Version], +) -> anyhow::Result<()> { + for version in versions { + add_asset(assets, version).await?; + } + + Ok(()) +} diff --git a/crates/xtask/src/test/workload.rs b/crates/xtask/src/test/workload.rs index faabbd479..b57994dea 100644 --- a/crates/xtask/src/test/workload.rs +++ b/crates/xtask/src/test/workload.rs @@ -8,19 +8,41 @@ use crate::{ client::Client, command::{run_commands, Command}, }, - test::TestDeriveArgs, + test::{versions::expand_assets_with_versions, TestDeriveArgs}, }; +#[derive(Clone)] +pub enum VersionOrLatest { + Version(Version), + Latest, +} + +impl<'a> Deserialize<'a> for VersionOrLatest { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'a>, + { + let s: &str = Deserialize::deserialize(deserializer)?; + + if s.eq_ignore_ascii_case("latest") { + Ok(VersionOrLatest::Latest) + } else { + let version = Version::parse(s).map_err(serde::de::Error::custom)?; + Ok(VersionOrLatest::Version(version)) + } + } +} + #[derive(Deserialize)] #[serde(untagged)] pub enum CommandOrUpgrade { Command(Command), - Upgrade { upgrade: Version }, + Upgrade { upgrade: VersionOrLatest }, } enum CommandOrUpgradeVec { Commands(Vec), - Upgrade(Version), + Upgrade(VersionOrLatest), } /// A test workload. @@ -34,17 +56,15 @@ pub struct TestWorkload { impl TestWorkload { pub async fn run( - &self, + &mut self, args: &TestDeriveArgs, assets_client: &Client, meili_client: &Client, ) -> anyhow::Result<()> { - // Fetch assets - fetch_assets(assets_client, &self.assets, &args.common.asset_folder).await?; - // Group commands between upgrades let mut commands_or_upgrade = Vec::new(); let mut current_commands = Vec::new(); + let mut all_versions = vec![args.initial_version.clone()]; for command_or_upgrade in &self.commands { match command_or_upgrade { CommandOrUpgrade::Command(command) => current_commands.push(command.clone()), @@ -54,10 +74,17 @@ impl TestWorkload { current_commands = Vec::new(); } commands_or_upgrade.push(CommandOrUpgradeVec::Upgrade(upgrade.clone())); + if let VersionOrLatest::Version(upgrade) = upgrade { + all_versions.push(upgrade.clone()); + } } } } + // Fetch assets + expand_assets_with_versions(&mut self.assets, &all_versions).await?; + fetch_assets(assets_client, &self.assets, &args.common.asset_folder).await?; + for command_or_upgrade in commands_or_upgrade { match command_or_upgrade { CommandOrUpgradeVec::Commands(commands) => {