mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-12-13 07:57:02 +00:00
Introduce the first working version of the tool
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7806,6 +7806,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ reqwest = { version = "0.12.24", features = [
|
|||||||
"json",
|
"json",
|
||||||
"rustls-tls",
|
"rustls-tls",
|
||||||
], default-features = false }
|
], default-features = false }
|
||||||
|
semver = "1.0.27"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn default_dashboard_url() -> String {
|
|||||||
|
|
||||||
/// Run benchmarks from a workload
|
/// Run benchmarks from a workload
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct BenchDeriveArgs {
|
pub struct BenchArgs {
|
||||||
/// Common arguments shared with other commands
|
/// Common arguments shared with other commands
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
common: CommonArgs,
|
common: CommonArgs,
|
||||||
@@ -59,7 +59,7 @@ pub struct BenchDeriveArgs {
|
|||||||
binary_path: Option<PathBuf>,
|
binary_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: BenchDeriveArgs) -> anyhow::Result<()> {
|
pub fn run(args: BenchArgs) -> anyhow::Result<()> {
|
||||||
setup_logs(&args.common.log_filter)?;
|
setup_logs(&args.common.log_filter)?;
|
||||||
|
|
||||||
// fetch environment and build info
|
// fetch environment and build info
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use tokio::task::JoinHandle;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::dashboard::DashboardClient;
|
use super::dashboard::DashboardClient;
|
||||||
use super::BenchDeriveArgs;
|
use super::BenchArgs;
|
||||||
use crate::common::assets::{self, Asset};
|
use crate::common::assets::{self, Asset};
|
||||||
use crate::common::client::Client;
|
use crate::common::client::Client;
|
||||||
use crate::common::command::{run_commands, Command};
|
use crate::common::command::{run_commands, Command};
|
||||||
@@ -40,7 +40,7 @@ async fn run_workload_commands(
|
|||||||
meili_client: &Arc<Client>,
|
meili_client: &Arc<Client>,
|
||||||
workload_uuid: Uuid,
|
workload_uuid: Uuid,
|
||||||
workload: &BenchWorkload,
|
workload: &BenchWorkload,
|
||||||
args: &BenchDeriveArgs,
|
args: &BenchArgs,
|
||||||
run_number: u16,
|
run_number: u16,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<File>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<File>>> {
|
||||||
let report_folder = &args.report_folder;
|
let report_folder = &args.report_folder;
|
||||||
@@ -95,7 +95,7 @@ pub async fn execute(
|
|||||||
invocation_uuid: Uuid,
|
invocation_uuid: Uuid,
|
||||||
master_key: Option<&str>,
|
master_key: Option<&str>,
|
||||||
workload: BenchWorkload,
|
workload: BenchWorkload,
|
||||||
args: &BenchDeriveArgs,
|
args: &BenchArgs,
|
||||||
binary_path: Option<&Path>,
|
binary_path: Option<&Path>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
assets::fetch_assets(assets_client, &workload.assets, &args.common.asset_folder).await?;
|
assets::fetch_assets(assets_client, &workload.assets, &args.common.asset_folder).await?;
|
||||||
@@ -143,7 +143,7 @@ async fn execute_run(
|
|||||||
workload_uuid: Uuid,
|
workload_uuid: Uuid,
|
||||||
master_key: Option<&str>,
|
master_key: Option<&str>,
|
||||||
workload: &BenchWorkload,
|
workload: &BenchWorkload,
|
||||||
args: &BenchDeriveArgs,
|
args: &BenchArgs,
|
||||||
binary_path: Option<&Path>,
|
binary_path: Option<&Path>,
|
||||||
run_number: u16,
|
run_number: u16,
|
||||||
) -> anyhow::Result<tokio::task::JoinHandle<anyhow::Result<std::fs::File>>> {
|
) -> anyhow::Result<tokio::task::JoinHandle<anyhow::Result<std::fs::File>>> {
|
||||||
|
|||||||
@@ -1,16 +1,34 @@
|
|||||||
use std::collections::HashSet;
|
use std::{collections::HashSet, process::Stdio};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use xtask::{bench::BenchDeriveArgs, test::TestDeriveArgs};
|
use semver::{Prerelease, Version};
|
||||||
|
use xtask::{bench::BenchArgs, test::TestArgs};
|
||||||
|
|
||||||
|
/// This is the version of the crate but also the current Meilisearch version
|
||||||
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
/// List features available in the workspace
|
/// List features available in the workspace
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct ListFeaturesDeriveArgs {
|
struct ListFeaturesArgs {
|
||||||
/// Feature to exclude from the list. Use a comma to separate multiple features.
|
/// Feature to exclude from the list. Use a comma to separate multiple features.
|
||||||
#[arg(short, long, value_delimiter = ',')]
|
#[arg(short, long, value_delimiter = ',')]
|
||||||
exclude_feature: Vec<String>,
|
exclude_feature: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a git tag for the current version
|
||||||
|
///
|
||||||
|
/// The tag will of the form prototype-v<version>-<name>.<increment>
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
struct PrototypeArgs {
|
||||||
|
/// Name of the prototype to generate
|
||||||
|
name: String,
|
||||||
|
/// If true refuses to increment the tag if it already exists
|
||||||
|
/// else refuses to generate new tag and expect the tag to exist.
|
||||||
|
#[arg(long)]
|
||||||
|
generate_new: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Utilitary commands
|
/// Utilitary commands
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about)]
|
#[command(author, version, about, long_about)]
|
||||||
@@ -18,9 +36,10 @@ struct ListFeaturesDeriveArgs {
|
|||||||
#[command(bin_name = "cargo xtask")]
|
#[command(bin_name = "cargo xtask")]
|
||||||
#[allow(clippy::large_enum_variant)] // please, that's enough...
|
#[allow(clippy::large_enum_variant)] // please, that's enough...
|
||||||
enum Command {
|
enum Command {
|
||||||
ListFeatures(ListFeaturesDeriveArgs),
|
ListFeatures(ListFeaturesArgs),
|
||||||
Bench(BenchDeriveArgs),
|
Bench(BenchArgs),
|
||||||
Test(TestDeriveArgs),
|
GeneratePrototype(PrototypeArgs),
|
||||||
|
Test(TestArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@@ -28,12 +47,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
match args {
|
match args {
|
||||||
Command::ListFeatures(args) => list_features(args),
|
Command::ListFeatures(args) => list_features(args),
|
||||||
Command::Bench(args) => xtask::bench::run(args)?,
|
Command::Bench(args) => xtask::bench::run(args)?,
|
||||||
|
Command::GeneratePrototype(args) => generate_prototype(args)?,
|
||||||
Command::Test(args) => xtask::test::run(args)?,
|
Command::Test(args) => xtask::test::run(args)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_features(args: ListFeaturesDeriveArgs) {
|
fn list_features(args: ListFeaturesArgs) {
|
||||||
let exclude_features: HashSet<_> = args.exclude_feature.into_iter().collect();
|
let exclude_features: HashSet<_> = args.exclude_feature.into_iter().collect();
|
||||||
let metadata = cargo_metadata::MetadataCommand::new().no_deps().exec().unwrap();
|
let metadata = cargo_metadata::MetadataCommand::new().no_deps().exec().unwrap();
|
||||||
let features: Vec<String> = metadata
|
let features: Vec<String> = metadata
|
||||||
@@ -46,3 +66,106 @@ fn list_features(args: ListFeaturesDeriveArgs) {
|
|||||||
let features = features.join(" ");
|
let features = features.join(" ");
|
||||||
println!("{features}")
|
println!("{features}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_prototype(args: PrototypeArgs) -> anyhow::Result<()> {
|
||||||
|
let PrototypeArgs { name, generate_new: create_new } = args;
|
||||||
|
|
||||||
|
if name.rsplit_once(['.', '-']).filter(|(_, t)| t.chars().all(char::is_numeric)).is_some() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"The increment must not be part of the name and will be rather incremented by this command."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Fetch the crate version
|
||||||
|
let version = Version::parse(VERSION).context("while semver-parsing the crate version")?;
|
||||||
|
|
||||||
|
// 2. Pull tags from remote and retrieve last prototype tag
|
||||||
|
std::process::Command::new("git")
|
||||||
|
.arg("fetch")
|
||||||
|
.arg("--tags")
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.stdout(Stdio::inherit())
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
let output = std::process::Command::new("git")
|
||||||
|
.arg("tag")
|
||||||
|
.args(["--list", "prototype-v*"])
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.output()?;
|
||||||
|
let output =
|
||||||
|
String::try_from(output.stdout).context("while converting the tag list into a string")?;
|
||||||
|
|
||||||
|
let mut highest_increment = None;
|
||||||
|
for tag in output.lines() {
|
||||||
|
let Some(version) = tag.strip_prefix("prototype-v") else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Ok(version) = Version::parse(version) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Ok(proto) = PrototypePrerelease::from_str(version.pre.as_str()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if proto.name() == name {
|
||||||
|
highest_increment = match highest_increment {
|
||||||
|
Some(last) if last < proto.increment() => Some(proto.increment()),
|
||||||
|
Some(last) => Some(last),
|
||||||
|
None => Some(proto.increment()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Generate the new tag name (without git, just a string)
|
||||||
|
let increment = match (create_new, highest_increment) {
|
||||||
|
(true, None) => 0,
|
||||||
|
(true, Some(increment)) => anyhow::bail!(
|
||||||
|
"A prototype with the name `{name}` already exists with increment `{increment}`"
|
||||||
|
),
|
||||||
|
(false, None) => anyhow::bail!(
|
||||||
|
"Prototype `{name}` is missing and must exist to be incremented.\n\
|
||||||
|
Use the --generate-new flag to create a new prototype with an increment at 0."
|
||||||
|
),
|
||||||
|
(false, Some(increment)) => {
|
||||||
|
increment.checked_add(1).context("While incrementing by one the increment")?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note that we cannot have leading zeros in the increment
|
||||||
|
let pre = format!("{name}.{increment}").parse().context("while parsing pre-release name")?;
|
||||||
|
let tag_name = Version { pre, ..version };
|
||||||
|
println!("prototype-v{tag_name}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct PrototypePrerelease {
|
||||||
|
pre: Prerelease,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrototypePrerelease {
|
||||||
|
fn from_str(s: &str) -> anyhow::Result<Self> {
|
||||||
|
Prerelease::new(s)
|
||||||
|
.map_err(Into::into)
|
||||||
|
.and_then(|pre| {
|
||||||
|
if pre.rsplit_once('.').is_some() {
|
||||||
|
Ok(pre)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Invalid prototype name, missing name or increment"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|pre| PrototypePrerelease { pre })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.pre.rsplit_once('.').expect("Missing prototype name").0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&self) -> u32 {
|
||||||
|
self.pre
|
||||||
|
.as_str()
|
||||||
|
.rsplit_once('.')
|
||||||
|
.map(|(_, tail)| tail.parse().expect("Invalid increment"))
|
||||||
|
.expect("Missing increment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub use workload::TestWorkload;
|
|||||||
|
|
||||||
/// Run tests from a workload
|
/// Run tests from a workload
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct TestDeriveArgs {
|
pub struct TestArgs {
|
||||||
/// Common arguments shared with other commands
|
/// Common arguments shared with other commands
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
common: CommonArgs,
|
common: CommonArgs,
|
||||||
@@ -31,7 +31,7 @@ pub struct TestDeriveArgs {
|
|||||||
pub add_missing_responses: bool,
|
pub add_missing_responses: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(args: TestDeriveArgs) -> anyhow::Result<()> {
|
pub fn run(args: TestArgs) -> anyhow::Result<()> {
|
||||||
let rt = tokio::runtime::Builder::new_current_thread().enable_io().enable_time().build()?;
|
let rt = tokio::runtime::Builder::new_current_thread().enable_io().enable_time().build()?;
|
||||||
let _scope = rt.enter();
|
let _scope = rt.enter();
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ pub fn run(args: TestDeriveArgs) -> anyhow::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_inner(args: TestDeriveArgs) -> anyhow::Result<()> {
|
async fn run_inner(args: TestArgs) -> anyhow::Result<()> {
|
||||||
setup_logs(&args.common.log_filter)?;
|
setup_logs(&args.common.log_filter)?;
|
||||||
|
|
||||||
// setup clients
|
// setup clients
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::common::command::{run_commands, Command};
|
|||||||
use crate::common::instance::Binary;
|
use crate::common::instance::Binary;
|
||||||
use crate::common::process::{self, delete_db, kill_meili};
|
use crate::common::process::{self, delete_db, kill_meili};
|
||||||
use crate::common::workload::Workload;
|
use crate::common::workload::Workload;
|
||||||
use crate::test::TestDeriveArgs;
|
use crate::test::TestArgs;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
@@ -81,7 +81,7 @@ pub struct TestWorkload {
|
|||||||
impl TestWorkload {
|
impl TestWorkload {
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
mut self,
|
mut self,
|
||||||
args: &TestDeriveArgs,
|
args: &TestArgs,
|
||||||
assets_client: &Client,
|
assets_client: &Client,
|
||||||
meili_client: &Arc<Client>,
|
meili_client: &Arc<Client>,
|
||||||
asset_folder: &'static str,
|
asset_folder: &'static str,
|
||||||
|
|||||||
Reference in New Issue
Block a user