aboutsummaryrefslogtreecommitdiff
path: root/release
diff options
context:
space:
mode:
Diffstat (limited to 'release')
-rw-r--r--release/Cargo.toml8
-rw-r--r--release/src/semver_check.rs93
2 files changed, 86 insertions, 15 deletions
diff --git a/release/Cargo.toml b/release/Cargo.toml
index 7875d088a..9701a76e5 100644
--- a/release/Cargo.toml
+++ b/release/Cargo.toml
@@ -18,10 +18,10 @@ log = "0.4"
18simple_logger = "5.0.0" 18simple_logger = "5.0.0"
19temp-file = "0.1.9" 19temp-file = "0.1.9"
20flate2 = "1.1.1" 20flate2 = "1.1.1"
21 21crates-index = "3.11.0"
22[patch.crates-io] 22tar = "0.4"
23cargo-semver-checks = { git = "https://github.com/lulf/cargo-semver-checks.git", rev="385f274edcbb6bf5156e30a94315852b27a527e6" } 23reqwest = { version = "0.12", features = ["blocking"] }
24#cargo-semver-checks = { path = "../../cargo-semver-checks" } 24cargo-manifest = "0.19.1"
25 25
26[package.metadata.embassy] 26[package.metadata.embassy]
27skip = true 27skip = true
diff --git a/release/src/semver_check.rs b/release/src/semver_check.rs
index a4a9e77b5..4cfa26ec0 100644
--- a/release/src/semver_check.rs
+++ b/release/src/semver_check.rs
@@ -1,6 +1,11 @@
1use std::collections::HashSet;
1use std::path::PathBuf; 2use std::path::PathBuf;
3use std::{env, fs};
2 4
3use cargo_semver_checks::{Check, GlobalConfig, LintConfig, LintLevel, ReleaseType, RequiredSemverUpdate, Rustdoc}; 5use anyhow::anyhow;
6use cargo_semver_checks::{Check, GlobalConfig, ReleaseType, RequiredSemverUpdate, Rustdoc};
7use flate2::read::GzDecoder;
8use tar::Archive;
4 9
5use crate::cargo::CargoArgsBuilder; 10use crate::cargo::CargoArgsBuilder;
6use crate::types::{BuildConfig, Crate}; 11use crate::types::{BuildConfig, Crate};
@@ -11,12 +16,18 @@ pub fn minimum_update(krate: &Crate) -> Result<ReleaseType, anyhow::Error> {
11 let config = krate.configs.first().unwrap(); // TODO 16 let config = krate.configs.first().unwrap(); // TODO
12 17
13 let package_name = krate.name.clone(); 18 let package_name = krate.name.clone();
14 let current_path = build_doc_json(krate, config)?; 19 let baseline_path = download_baseline(&package_name, &krate.version)?;
20 let mut baseline_krate = krate.clone();
21 baseline_krate.path = baseline_path;
15 22
16 // TODO: Prevent compiler panic on current compiler version 23 // Compare features as it's not covered by semver-checks
17 std::env::set_var("RUSTFLAGS", "--cap-lints=warn"); 24 if compare_features(&baseline_krate, &krate)? {
25 return Ok(ReleaseType::Minor);
26 }
27 let baseline_path = build_doc_json(&baseline_krate, config)?;
28 let current_path = build_doc_json(krate, config)?;
18 29
19 let baseline = Rustdoc::from_registry_latest_crate_version(); 30 let baseline = Rustdoc::from_path(&baseline_path);
20 let doc = Rustdoc::from_path(&current_path); 31 let doc = Rustdoc::from_path(&current_path);
21 let mut semver_check = Check::new(doc); 32 let mut semver_check = Check::new(doc);
22 semver_check.with_default_features(); 33 semver_check.with_default_features();
@@ -29,12 +40,8 @@ pub fn minimum_update(krate: &Crate) -> Result<ReleaseType, anyhow::Error> {
29 semver_check.set_build_target(target.clone()); 40 semver_check.set_build_target(target.clone());
30 } 41 }
31 let mut cfg = GlobalConfig::new(); 42 let mut cfg = GlobalConfig::new();
32 cfg.set_log_level(Some(log::Level::Trace)); 43 cfg.set_log_level(Some(log::Level::Info));
33 44
34 let mut lint_cfg = LintConfig::new();
35 // Disable this lint because we provide the rustdoc json only, so it can't do feature comparison.
36 lint_cfg.set("feature_missing", LintLevel::Allow, RequiredSemverUpdate::Minor, 0);
37 cfg.set_lint_config(lint_cfg);
38 let result = semver_check.check_release(&mut cfg)?; 45 let result = semver_check.check_release(&mut cfg)?;
39 46
40 let mut min_required_update = ReleaseType::Patch; 47 let mut min_required_update = ReleaseType::Patch;
@@ -51,7 +58,71 @@ pub fn minimum_update(krate: &Crate) -> Result<ReleaseType, anyhow::Error> {
51 Ok(min_required_update) 58 Ok(min_required_update)
52} 59}
53 60
54pub(crate) fn build_doc_json(krate: &Crate, config: &BuildConfig) -> Result<PathBuf, anyhow::Error> { 61fn compare_features(old: &Crate, new: &Crate) -> Result<bool, anyhow::Error> {
62 let mut old = read_features(&old.path)?;
63 let new = read_features(&new.path)?;
64
65 old.retain(|r| !new.contains(r));
66 log::info!("Features removed in new: {:?}", old);
67 Ok(!old.is_empty())
68}
69
70fn download_baseline(name: &str, version: &str) -> Result<PathBuf, anyhow::Error> {
71 let config = crates_index::IndexConfig {
72 dl: "https://crates.io/api/v1/crates".to_string(),
73 api: Some("https://crates.io".to_string()),
74 };
75
76 let url =
77 config
78 .download_url(name, version)
79 .ok_or(anyhow!("unable to download baseline for {}-{}", name, version))?;
80
81 let parent_dir = env::var("RELEASER_CACHE").map_err(|_| anyhow!("RELEASER_CACHE not set"))?;
82
83 let extract_path = PathBuf::from(&parent_dir).join(format!("{}-{}", name, version));
84
85 if extract_path.exists() {
86 return Ok(extract_path);
87 }
88
89 let response = reqwest::blocking::get(url)?;
90 let bytes = response.bytes()?;
91
92 let decoder = GzDecoder::new(&bytes[..]);
93 let mut archive = Archive::new(decoder);
94 archive.unpack(&parent_dir)?;
95
96 Ok(extract_path)
97}
98
99fn read_features(crate_path: &PathBuf) -> Result<HashSet<String>, anyhow::Error> {
100 let cargo_toml_path = crate_path.join("Cargo.toml");
101
102 if !cargo_toml_path.exists() {
103 return Err(anyhow!("Cargo.toml not found at {:?}", cargo_toml_path));
104 }
105
106 let manifest = cargo_manifest::Manifest::from_path(&cargo_toml_path)?;
107
108 let mut set = HashSet::new();
109 if let Some(features) = manifest.features {
110 for f in features.keys() {
111 set.insert(f.clone());
112 }
113 }
114 if let Some(deps) = manifest.dependencies {
115 for (k, v) in deps.iter() {
116 if v.optional() {
117 set.insert(k.clone());
118 }
119 }
120 }
121
122 Ok(set)
123}
124
125fn build_doc_json(krate: &Crate, config: &BuildConfig) -> Result<PathBuf, anyhow::Error> {
55 let target_dir = std::env::var("CARGO_TARGET_DIR"); 126 let target_dir = std::env::var("CARGO_TARGET_DIR");
56 127
57 let target_path = if let Ok(target) = target_dir { 128 let target_path = if let Ok(target) = target_dir {