mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00
Add subcommand to rollover migration guides (#3606)
* add subcommand to create migration guides * make git changes
This commit is contained in:
parent
1f1e120dd2
commit
71fe3f0e46
@ -5,6 +5,8 @@ pub mod bump_version;
|
||||
pub mod execute_plan;
|
||||
#[cfg(feature = "release")]
|
||||
pub mod plan;
|
||||
#[cfg(feature = "release")]
|
||||
pub mod post_release;
|
||||
pub mod publish;
|
||||
#[cfg(feature = "release")]
|
||||
pub mod publish_plan;
|
||||
@ -21,6 +23,10 @@ pub use publish::*;
|
||||
pub use publish_plan::*;
|
||||
pub use semver_check::*;
|
||||
pub use tag_releases::*;
|
||||
#[cfg(feature = "release")]
|
||||
pub use post_release::*;
|
||||
|
||||
pub const PLACEHOLDER: &str = "{{currentVersion}}";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Subcommands
|
||||
@ -47,6 +53,10 @@ pub enum Release {
|
||||
/// the release and pushes the tags.
|
||||
#[cfg(feature = "release")]
|
||||
PublishPlan(PublishPlanArgs),
|
||||
/// Rollover migrations steps post release.
|
||||
/// - Create new migration guides for packages that have a migration guide
|
||||
#[cfg(feature = "release")]
|
||||
PostRelease,
|
||||
/// Bump the version of the specified package(s).
|
||||
///
|
||||
/// This command will, for each specified package:
|
||||
|
@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
use toml_edit::{Item, TableLike, Value};
|
||||
|
||||
use crate::{Package, Version, cargo::CargoToml, changelog::Changelog};
|
||||
use crate::{cargo::CargoToml, changelog::Changelog, commands::PLACEHOLDER, Package, Version};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum VersionBump {
|
||||
@ -308,8 +308,6 @@ fn finalize_placeholders(
|
||||
new_version: &semver::Version,
|
||||
dry_run: bool,
|
||||
) -> Result<()> {
|
||||
const PLACEHOLDER: &str = "{{currentVersion}}";
|
||||
|
||||
let skip_paths = [bumped_package.package_path().join("target")];
|
||||
|
||||
fn walk_dir(dir: &Path, skip_paths: &[PathBuf], callback: &mut impl FnMut(&Path)) {
|
||||
|
@ -98,7 +98,10 @@ pub fn execute_plan(workspace: &Path, args: ApplyPlanArgs) -> Result<()> {
|
||||
);
|
||||
}
|
||||
|
||||
make_git_changes(!args.no_dry_run, &plan_source, &plan)?;
|
||||
let branch = make_git_changes(!args.no_dry_run, "release-branch", "Finalize crate releases")?;
|
||||
|
||||
open_pull_request(&branch, !args.no_dry_run, &plan_source, &plan)
|
||||
.with_context(|| "Failed to open pull request")?;
|
||||
|
||||
if !args.no_dry_run {
|
||||
println!(
|
||||
@ -109,12 +112,16 @@ pub fn execute_plan(workspace: &Path, args: ApplyPlanArgs) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_git_changes(dry_run: bool, release_plan_str: &str, release_plan: &Plan) -> Result<()> {
|
||||
pub(crate) struct Branch {
|
||||
pub name: String,
|
||||
pub upstream: String,
|
||||
}
|
||||
|
||||
pub(crate) fn make_git_changes(dry_run: bool, branch_name: &str, commit: &str) -> Result<Branch> {
|
||||
// Find an available branch name
|
||||
let branch_name = format!(
|
||||
"{branch_name}-{}",
|
||||
jiff::Timestamp::now().strftime("%Y-%m-%d"),
|
||||
branch_name = "release-branch",
|
||||
);
|
||||
|
||||
let upstream = get_remote_name_for("esp-rs/esp-hal")?;
|
||||
@ -140,10 +147,11 @@ fn make_git_changes(dry_run: bool, release_plan_str: &str, release_plan: &Plan)
|
||||
if dry_run {
|
||||
println!("Dry run: would commit changes to branch: {branch_name}");
|
||||
} else {
|
||||
Command::new("git").arg("add").arg(".").status().context("Failed to stage changes")?;
|
||||
Command::new("git")
|
||||
.arg("commit")
|
||||
.arg("-am")
|
||||
.arg("Finalize crates for release")
|
||||
.arg("-m")
|
||||
.arg(commit)
|
||||
.status()
|
||||
.context("Failed to commit changes")?;
|
||||
}
|
||||
@ -174,6 +182,18 @@ fn make_git_changes(dry_run: bool, release_plan_str: &str, release_plan: &Plan)
|
||||
extract_url_from_push(&String::from_utf8_lossy(&message.stderr)) // git outputs to stderr
|
||||
};
|
||||
|
||||
Ok(Branch {
|
||||
name: branch_name,
|
||||
upstream: url,
|
||||
})
|
||||
}
|
||||
|
||||
fn open_pull_request(
|
||||
branch: &Branch,
|
||||
dry_run: bool,
|
||||
release_plan_str: &str,
|
||||
release_plan: &Plan,
|
||||
) -> Result<()> {
|
||||
// Open a pull request
|
||||
|
||||
let packages_to_release = release_plan
|
||||
@ -216,7 +236,7 @@ cargo xrelease publish-plan --no-dry-run
|
||||
// TODO: don't forget to update the PR text once we have the `publish` command
|
||||
// updated.
|
||||
|
||||
let pr_url_base = comparison_url(&release_plan.base, &url, &branch_name)?;
|
||||
let pr_url_base = comparison_url(&release_plan.base, &branch.upstream, &branch.name)?;
|
||||
|
||||
// Query string options are documented at: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/using-query-parameters-to-create-a-pull-request
|
||||
let mut open_pr_url = format!(
|
||||
@ -254,7 +274,6 @@ cargo xrelease publish-plan --no-dry-run
|
||||
}
|
||||
|
||||
println!("Create the release PR and follow the next steps laid out there.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -268,7 +287,7 @@ fn extract_url_from_push(output: &str) -> String {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn comparison_url(base: &str, url: &str, branch_name: &str) -> Result<String> {
|
||||
pub(crate) fn comparison_url(base: &str, url: &str, branch_name: &str) -> Result<String> {
|
||||
let url = if url.starts_with("https://github.com/esp-rs/") {
|
||||
format!("https://github.com/esp-rs/esp-hal/compare/{base}...{branch_name}")
|
||||
} else {
|
||||
|
81
xtask/src/commands/release/post_release.rs
Normal file
81
xtask/src/commands/release/post_release.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use std::fs;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use semver::Version;
|
||||
use super::execute_plan::make_git_changes;
|
||||
use super::PLACEHOLDER;
|
||||
use super::Plan;
|
||||
use crate::commands::comparison_url;
|
||||
|
||||
pub fn post_release(workspace: &std::path::Path) -> Result<()> {
|
||||
// Read the release plan
|
||||
let plan_path = workspace.join("release_plan.jsonc");
|
||||
let plan_path = crate::windows_safe_path(&plan_path);
|
||||
|
||||
let plan = Plan::from_path(&plan_path)
|
||||
.with_context(|| format!("Failed to read release plan from {}", plan_path.display()))?;
|
||||
|
||||
// Process packages from the plan that have migration guides
|
||||
for package_plan in plan.packages.iter() {
|
||||
let package = package_plan.package;
|
||||
|
||||
if !package.has_migration_guide(workspace) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the package's directory path
|
||||
let package_path = workspace.join(package.to_string());
|
||||
let cargo_toml_path = package_path.join("Cargo.toml");
|
||||
|
||||
// Read and parse Cargo.toml
|
||||
let cargo_toml_content = fs::read_to_string(&cargo_toml_path)?;
|
||||
let cargo_toml = cargo_toml_content.parse::<toml_edit::DocumentMut>()?;
|
||||
|
||||
// Extract version from Cargo.toml
|
||||
let version_str = cargo_toml["package"]["version"].as_str().ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"Could not find version in Cargo.toml for package {:?}",
|
||||
package
|
||||
)
|
||||
})?;
|
||||
|
||||
// Parse version using semver and zero out patch version
|
||||
let mut version = Version::parse(version_str)?;
|
||||
version.patch = 0;
|
||||
|
||||
// Generate migration guide filename
|
||||
let migration_file_name = format!("MIGRATING-{}.md", version);
|
||||
let migration_file_path = package_path.join(&migration_file_name);
|
||||
|
||||
// Create the migration guide file if it doesn't exist
|
||||
if !migration_file_path.exists() {
|
||||
// Create the title content
|
||||
let title = format!("# Migration Guide from {} to {}\n", version, PLACEHOLDER);
|
||||
fs::write(&migration_file_path, title)?;
|
||||
log::info!("Created migration guide: {}", migration_file_path.display());
|
||||
} else {
|
||||
log::info!(
|
||||
"Migration guide already exists: {}",
|
||||
migration_file_path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let branch = make_git_changes(false, "post-release-branch", "Post release rollover")?;
|
||||
|
||||
println!("Post-release migration guides created successfully.");
|
||||
|
||||
let pr_url_base = comparison_url(&plan.base, &branch.upstream, &branch.name)?;
|
||||
|
||||
let open_pr_url = format!(
|
||||
"{pr_url_base}?quick_pull=1&title=Post+release+rollover&labels={labels}",
|
||||
labels = "skip-changelog",
|
||||
);
|
||||
|
||||
if opener::open(&open_pr_url).is_err() {
|
||||
println!("Open the following URL to create a pull request:");
|
||||
println!("{open_pr_url}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -106,6 +106,26 @@ impl Package {
|
||||
.any(|line| line.contains("asm_experimental_arch"))
|
||||
}
|
||||
|
||||
pub fn has_migration_guide(&self, workspace: &Path) -> bool {
|
||||
let package_path = workspace.join(self.to_string());
|
||||
|
||||
// Check if the package directory exists
|
||||
let Ok(entries) = std::fs::read_dir(&package_path) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Look for files matching the pattern "MIGRATING-*.md"
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.starts_with("MIGRATING-") && file_name.ends_with(".md") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn needs_build_std(&self) -> bool {
|
||||
use Package::*;
|
||||
|
||||
|
@ -133,6 +133,8 @@ fn main() -> Result<()> {
|
||||
Release::ExecutePlan(args) => execute_plan(&workspace, args),
|
||||
#[cfg(feature = "release")]
|
||||
Release::PublishPlan(args) => publish_plan(&workspace, args),
|
||||
#[cfg(feature = "release")]
|
||||
Release::PostRelease => post_release(&workspace),
|
||||
},
|
||||
|
||||
Cli::Ci(args) => run_ci_checks(&workspace, args),
|
||||
|
Loading…
x
Reference in New Issue
Block a user