mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 06:40:47 +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"
|
log = "0.4.22"
|
||||||
minijinja = { version = "2.5.0", default-features = false }
|
minijinja = { version = "2.5.0", default-features = false }
|
||||||
opener = { version = "0.7.2", optional = true }
|
opener = { version = "0.7.2", optional = true }
|
||||||
|
regex = { version = "1.11.1", optional = true }
|
||||||
rocket = { version = "0.5.1", optional = true }
|
rocket = { version = "0.5.1", optional = true }
|
||||||
semver = { version = "1.0.23", features = ["serde"] }
|
semver = { version = "1.0.23", features = ["serde"] }
|
||||||
serde = { version = "1.0.215", default-features = false, features = ["derive"] }
|
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"]
|
deploy-docs = ["dep:reqwest", "dep:kuchikiki"]
|
||||||
preview-docs = ["dep:opener", "dep:rocket"]
|
preview-docs = ["dep:opener", "dep:rocket"]
|
||||||
semver-checks = [ "dep:cargo-semver-checks", "dep:rustdoc-types", "dep:flate2", "dep:temp-file" ]
|
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;
|
use clap::Subcommand;
|
||||||
|
|
||||||
|
#[cfg(feature = "release")]
|
||||||
|
pub mod bump_msrv;
|
||||||
pub mod bump_version;
|
pub mod bump_version;
|
||||||
#[cfg(feature = "release")]
|
#[cfg(feature = "release")]
|
||||||
pub mod execute_plan;
|
pub mod execute_plan;
|
||||||
@ -18,13 +20,13 @@ pub use bump_version::*;
|
|||||||
pub use execute_plan::*;
|
pub use execute_plan::*;
|
||||||
#[cfg(feature = "release")]
|
#[cfg(feature = "release")]
|
||||||
pub use plan::*;
|
pub use plan::*;
|
||||||
|
#[cfg(feature = "release")]
|
||||||
|
pub use post_release::*;
|
||||||
pub use publish::*;
|
pub use publish::*;
|
||||||
#[cfg(feature = "release")]
|
#[cfg(feature = "release")]
|
||||||
pub use publish_plan::*;
|
pub use publish_plan::*;
|
||||||
pub use semver_check::*;
|
pub use semver_check::*;
|
||||||
pub use tag_releases::*;
|
pub use tag_releases::*;
|
||||||
#[cfg(feature = "release")]
|
|
||||||
pub use post_release::*;
|
|
||||||
|
|
||||||
pub const PLACEHOLDER: &str = "{{currentVersion}}";
|
pub const PLACEHOLDER: &str = "{{currentVersion}}";
|
||||||
|
|
||||||
@ -73,4 +75,8 @@ pub enum Release {
|
|||||||
Publish(PublishArgs),
|
Publish(PublishArgs),
|
||||||
/// Generate git tags for all new package releases.
|
/// Generate git tags for all new package releases.
|
||||||
TagReleases(TagReleasesArgs),
|
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),
|
Release::PublishPlan(args) => publish_plan(&workspace, args),
|
||||||
#[cfg(feature = "release")]
|
#[cfg(feature = "release")]
|
||||||
Release::PostRelease => post_release(&workspace),
|
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),
|
Cli::Ci(args) => run_ci_checks(&workspace, args),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user