mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
xtask: msrv-bump (#3708)
* Add bump-msrv command * Make regex dependency optional * Adjustments * Make bump-msrv a release sub-command * Don't assume to bump MSRV for all packages always * Check Check * Re-arrange code * Remove controversial CLI-switch
This commit is contained in:
parent
0f73826a81
commit
0137fbb5c4
@ -15,6 +15,7 @@ kuchikiki = { version = "0.8.2", optional = true }
|
||||
log = "0.4.22"
|
||||
minijinja = { version = "2.5.0", default-features = false }
|
||||
opener = { version = "0.7.2", optional = true }
|
||||
regex = { version = "1.11.1", optional = true }
|
||||
rocket = { version = "0.5.1", optional = true }
|
||||
semver = { version = "1.0.23", features = ["serde"] }
|
||||
serde = { version = "1.0.215", default-features = false, features = ["derive"] }
|
||||
@ -47,4 +48,4 @@ pretty_assertions = "1.2.0"
|
||||
deploy-docs = ["dep:reqwest", "dep:kuchikiki"]
|
||||
preview-docs = ["dep:opener", "dep:rocket"]
|
||||
semver-checks = [ "dep:cargo-semver-checks", "dep:rustdoc-types", "dep:flate2", "dep:temp-file" ]
|
||||
release = ["semver-checks", "dep:opener", "dep:urlencoding"]
|
||||
release = ["semver-checks", "dep:opener", "dep:urlencoding", "dep:regex"]
|
||||
|
@ -1,5 +1,7 @@
|
||||
use clap::Subcommand;
|
||||
|
||||
#[cfg(feature = "release")]
|
||||
pub mod bump_msrv;
|
||||
pub mod bump_version;
|
||||
#[cfg(feature = "release")]
|
||||
pub mod execute_plan;
|
||||
@ -18,13 +20,13 @@ pub use bump_version::*;
|
||||
pub use execute_plan::*;
|
||||
#[cfg(feature = "release")]
|
||||
pub use plan::*;
|
||||
#[cfg(feature = "release")]
|
||||
pub use post_release::*;
|
||||
pub use publish::*;
|
||||
#[cfg(feature = "release")]
|
||||
pub use publish_plan::*;
|
||||
pub use semver_check::*;
|
||||
pub use tag_releases::*;
|
||||
#[cfg(feature = "release")]
|
||||
pub use post_release::*;
|
||||
|
||||
pub const PLACEHOLDER: &str = "{{currentVersion}}";
|
||||
|
||||
@ -73,4 +75,8 @@ pub enum Release {
|
||||
Publish(PublishArgs),
|
||||
/// Generate git tags for all new package releases.
|
||||
TagReleases(TagReleasesArgs),
|
||||
/// Update the MSRV (Badges in README.md, "rust-version" in Cargo.toml, the
|
||||
/// toolchain used in CI)
|
||||
#[cfg(feature = "release")]
|
||||
BumpMsrv(bump_msrv::BumpMsrvArgs),
|
||||
}
|
||||
|
190
xtask/src/commands/release/bump_msrv.rs
Normal file
190
xtask/src/commands/release/bump_msrv.rs
Normal file
@ -0,0 +1,190 @@
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use clap::Args;
|
||||
use regex::{Captures, Regex};
|
||||
use strum::IntoEnumIterator;
|
||||
use toml_edit::value;
|
||||
|
||||
use crate::{Package, cargo::CargoToml};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct BumpMsrvArgs {
|
||||
/// The MSRV to be used
|
||||
#[arg(long)]
|
||||
pub msrv: String,
|
||||
|
||||
/// Package(s) to target.
|
||||
#[arg(value_enum, default_values_t = Package::iter())]
|
||||
pub packages: Vec<Package>,
|
||||
|
||||
/// Don't actually change any files
|
||||
#[arg(long)]
|
||||
pub dry_run: bool,
|
||||
}
|
||||
|
||||
/// Bump the MSRV
|
||||
///
|
||||
/// This will process
|
||||
/// - `Cargo.toml` for the packages (adjust (or add if not present) the
|
||||
/// "rust-version")
|
||||
/// - `README.md` for the packages if it exists (adjusts the MSRV badge)
|
||||
/// - IF the esp-hal package was touched: .github/workflows/ci.yml (adapts the
|
||||
/// `MSRV: "<msrv>"` entry)
|
||||
///
|
||||
/// Non-published packages are not touched.
|
||||
///
|
||||
/// If it detects a package which other packages in the repo depend on it will
|
||||
/// also apply the changes there. (Can be disabled)
|
||||
pub fn bump_msrv(workspace: &Path, args: BumpMsrvArgs) -> Result<()> {
|
||||
let new_msrv = semver::Version::parse(&args.msrv)?;
|
||||
if !new_msrv.pre.is_empty() || !new_msrv.build.is_empty() {
|
||||
bail!("Invalid MSRV: {}", args.msrv);
|
||||
}
|
||||
|
||||
let mut to_process = args.packages.clone();
|
||||
|
||||
// add crates which depend on any of the packages to bump
|
||||
add_dependent_crates(workspace, &mut to_process)?;
|
||||
|
||||
// don't process crates which are not published
|
||||
let to_process: Vec<Package> = to_process
|
||||
.iter()
|
||||
.filter(|pkg| {
|
||||
let cargo_toml = CargoToml::new(workspace, **pkg).unwrap();
|
||||
cargo_toml.is_published()
|
||||
})
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
let adjust_ci = to_process.contains(&Package::EspHal);
|
||||
|
||||
// process packages
|
||||
let badge_re = Regex::new(
|
||||
r"(?<prefix>https://img.shields.io/badge/MSRV-)(?<msrv>[0123456789.]*)(?<postfix>-)",
|
||||
)?;
|
||||
for package in to_process {
|
||||
println!("Processing {package}");
|
||||
let mut cargo_toml = CargoToml::new(workspace, package)?;
|
||||
let package_path = cargo_toml.package_path();
|
||||
|
||||
let package_table = cargo_toml
|
||||
.manifest
|
||||
.as_table_mut()
|
||||
.get_mut("package")
|
||||
.and_then(|pkg| pkg.as_table_mut());
|
||||
|
||||
if let Some(package_table) = package_table {
|
||||
let mut previous_rust_version = None;
|
||||
if let Some(rust_version) = package_table.get_mut("rust-version") {
|
||||
let rust_version = rust_version.as_str().unwrap();
|
||||
if semver::Version::parse(&rust_version)? > new_msrv {
|
||||
bail!("Downgrading rust-version is not supported");
|
||||
}
|
||||
previous_rust_version = Some(rust_version.to_string())
|
||||
}
|
||||
|
||||
package_table["rust-version"] = value(&new_msrv.to_string());
|
||||
if !args.dry_run {
|
||||
cargo_toml.save()?;
|
||||
}
|
||||
|
||||
let readme_path = package_path.join("README.md");
|
||||
if readme_path.exists() {
|
||||
let readme = std::fs::read_to_string(&readme_path)?;
|
||||
let readme = badge_re.replace(&readme, |caps: &Captures| {
|
||||
format!("{}{new_msrv}{}", &caps["prefix"], &caps["postfix"])
|
||||
});
|
||||
|
||||
if !args.dry_run {
|
||||
std::fs::write(readme_path, readme.as_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
if !args.dry_run {
|
||||
if let Some(previous_rust_version) = previous_rust_version {
|
||||
check_mentions(&package_path, &previous_rust_version)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if adjust_ci {
|
||||
// process ".github/workflows/ci.yml"
|
||||
println!("Processing .github/workflows/ci.yml");
|
||||
let ci_yml_path = workspace.join(".github/workflows/ci.yml");
|
||||
|
||||
let ci_yml = std::fs::read_to_string(&ci_yml_path)?;
|
||||
let ci_yml = Regex::new("(MSRV:.*\\\")([0123456789.]*)(\\\")")?
|
||||
.replace(&ci_yml, |caps: &Captures| {
|
||||
format!("{}{new_msrv}{}", &caps[1], &caps[3])
|
||||
});
|
||||
if !args.dry_run {
|
||||
std::fs::write(ci_yml_path, ci_yml.as_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
println!("\nPlease review the changes before committing.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add all crates in the repo which depend on the given packages
|
||||
fn add_dependent_crates(
|
||||
workspace: &Path,
|
||||
pkgs_to_process: &mut Vec<Package>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
Ok(
|
||||
while {
|
||||
let mut added = false;
|
||||
|
||||
// iterate over ALL known crates
|
||||
for package in Package::iter() {
|
||||
let mut cargo_toml = CargoToml::new(workspace, package.clone())?;
|
||||
|
||||
// iterate the dependencies in the repo
|
||||
for dep in cargo_toml.repo_dependencies() {
|
||||
let dependency_should_be_processed = pkgs_to_process.contains(&dep);
|
||||
let current_package_already_contained = pkgs_to_process.contains(&package);
|
||||
if dependency_should_be_processed && !current_package_already_contained {
|
||||
added = true;
|
||||
pkgs_to_process.push(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// break once we haven't added any more crates the to be processed list
|
||||
added
|
||||
} {},
|
||||
)
|
||||
}
|
||||
|
||||
/// Check files in the package and show if we find the version string in any
|
||||
/// file. Most probably it will report false positives but maybe not.
|
||||
fn check_mentions(package_path: &std::path::PathBuf, previous_rust_version: &str) -> Result<()> {
|
||||
for entry in walkdir::WalkDir::new(package_path)
|
||||
.into_iter()
|
||||
.filter_map(|entry| {
|
||||
let path = entry.unwrap().into_path();
|
||||
|
||||
if !path.is_file() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if path.components().any(|c| c.as_os_str() == "target") {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(path)
|
||||
})
|
||||
{
|
||||
let contents = std::fs::read_to_string(&entry)?;
|
||||
if contents.contains(previous_rust_version) {
|
||||
println!(
|
||||
"⚠️ '{previous_rust_version}' found in file {} - might be a false positive, otherwise consider adjusting the xtask.",
|
||||
entry.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -145,6 +145,8 @@ fn main() -> Result<()> {
|
||||
Release::PublishPlan(args) => publish_plan(&workspace, args),
|
||||
#[cfg(feature = "release")]
|
||||
Release::PostRelease => post_release(&workspace),
|
||||
#[cfg(feature = "release")]
|
||||
Release::BumpMsrv(args) => bump_msrv::bump_msrv(&workspace, args),
|
||||
},
|
||||
|
||||
Cli::Ci(args) => run_ci_checks(&workspace, args),
|
||||
|
Loading…
x
Reference in New Issue
Block a user