Skip to content

Commit 4ea60b0

Browse files
authored
fix(dev): sync release package versions (#7342)
1 parent 2562dfb commit 4ea60b0

File tree

1 file changed

+276
-24
lines changed

1 file changed

+276
-24
lines changed

dev/src/release/package.rs

Lines changed: 276 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::workspace_dir;
1919
use semver::Version;
2020
use std::path::{Path, PathBuf};
2121
use std::str::FromStr;
22+
use toml_edit::{DocumentMut, Item, TableLike};
2223

2324
#[derive(Debug, Clone)]
2425
pub struct Package {
@@ -65,7 +66,7 @@ pub fn all_packages() -> Vec<Package> {
6566
// Integrations
6667
let dav_server = make_package("integrations/dav-server", "0.7.0", vec![core.clone()]);
6768
let object_store = make_package("integrations/object_store", "0.55.0", vec![core.clone()]);
68-
let parquet = make_package("integrations/parquet", "0.7.0", vec![core.clone()]);
69+
let parquet = make_package("integrations/parquet", "0.8.0", vec![core.clone()]);
6970
let unftp_sbe = make_package("integrations/unftp-sbe", "0.4.0", vec![core.clone()]);
7071

7172
// Binaries moved to separate repositories; no longer released from this repo
@@ -93,46 +94,174 @@ pub fn all_packages() -> Vec<Package> {
9394

9495
pub fn update_package_version(package: &Package) -> bool {
9596
match package.name.as_str() {
96-
"core" => update_cargo_version(&package.path, &package.version),
97-
"integrations/dav-server" => update_cargo_version(&package.path, &package.version),
98-
"integrations/object_store" => update_cargo_version(&package.path, &package.version),
99-
"integrations/parquet" => update_cargo_version(&package.path, &package.version),
100-
"integrations/unftp-sbe" => update_cargo_version(&package.path, &package.version),
97+
"core" => update_cargo_version(&package.path, &package.version, package.dependencies()),
98+
"integrations/dav-server" => {
99+
update_cargo_version(&package.path, &package.version, package.dependencies())
100+
}
101+
"integrations/object_store" => {
102+
update_cargo_version(&package.path, &package.version, package.dependencies())
103+
}
104+
"integrations/parquet" => {
105+
update_cargo_version(&package.path, &package.version, package.dependencies())
106+
}
107+
"integrations/unftp-sbe" => {
108+
update_cargo_version(&package.path, &package.version, package.dependencies())
109+
}
101110

102111
"bindings/c" => false, // C bindings has no version to update
103112
"bindings/cpp" => false, // C++ bindings has no version to update
104113
"bindings/lua" => false, // Lua bindings has no version to update
105114

106-
"bindings/python" => update_cargo_version(&package.path, &package.version),
115+
"bindings/python" => update_cargo_version(&package.path, &package.version, &[]),
107116
"bindings/java" => update_maven_version(&package.path, &package.version),
108117
"bindings/nodejs" => update_nodejs_version(&package.path, &package.version),
109118

110119
name => panic!("unknown package: {name}"),
111120
}
112121
}
113122

114-
fn update_cargo_version(path: &Path, version: &Version) -> bool {
123+
fn update_cargo_version(path: &Path, version: &Version, dependencies: &[Package]) -> bool {
115124
let path = path.join("Cargo.toml");
116125
let manifest = std::fs::read_to_string(&path).unwrap();
117-
let mut manifest = toml_edit::DocumentMut::from_str(manifest.as_str()).unwrap();
126+
let mut manifest = DocumentMut::from_str(manifest.as_str()).unwrap();
127+
let mut updated = update_manifest_version(&mut manifest, version, &path);
118128

119-
let old_version = match manifest["package"]["version"].as_str() {
120-
Some(version) => Version::parse(version).unwrap(),
121-
None => panic!("missing version for package: {}", path.display()),
122-
};
129+
for dependency in dependencies {
130+
updated |= update_dependency_version(&mut manifest, dependency);
131+
}
123132

124-
if &old_version != version {
125-
manifest["package"]["version"] = toml_edit::value(version.to_string());
133+
if updated {
126134
std::fs::write(&path, manifest.to_string()).unwrap();
127-
println!(
128-
"updating version for package: {} from {} to {}",
129-
path.display(),
130-
old_version,
131-
version
132-
);
133-
true
134-
} else {
135-
false
135+
}
136+
137+
updated
138+
}
139+
140+
fn update_manifest_version(manifest: &mut DocumentMut, version: &Version, path: &Path) -> bool {
141+
if let Some(old_version) = manifest["package"]["version"]
142+
.as_str()
143+
.map(Version::parse)
144+
.transpose()
145+
.unwrap()
146+
{
147+
if &old_version != version {
148+
manifest["package"]["version"] = toml_edit::value(version.to_string());
149+
println!(
150+
"updating version for package: {} from {} to {}",
151+
path.display(),
152+
old_version,
153+
version
154+
);
155+
return true;
156+
}
157+
158+
return false;
159+
}
160+
161+
if let Some(old_version) = manifest["workspace"]["package"]["version"]
162+
.as_str()
163+
.map(Version::parse)
164+
.transpose()
165+
.unwrap()
166+
{
167+
if &old_version != version {
168+
manifest["workspace"]["package"]["version"] = toml_edit::value(version.to_string());
169+
println!(
170+
"updating version for package: {} from {} to {}",
171+
path.display(),
172+
old_version,
173+
version
174+
);
175+
return true;
176+
}
177+
178+
return false;
179+
}
180+
181+
panic!("missing version for package: {}", path.display());
182+
}
183+
184+
fn update_dependency_version(manifest: &mut DocumentMut, dependency: &Package) -> bool {
185+
let Some(crate_name) = dependency.crate_name() else {
186+
return false;
187+
};
188+
189+
update_dependency_version_in_table(manifest.as_table_mut(), crate_name, dependency)
190+
}
191+
192+
fn update_dependency_version_in_table(
193+
table: &mut dyn TableLike,
194+
crate_name: &str,
195+
dependency: &Package,
196+
) -> bool {
197+
let mut updated = false;
198+
199+
for table_name in ["dependencies", "dev-dependencies", "build-dependencies"] {
200+
let Some(dependencies) = table.get_mut(table_name).and_then(Item::as_table_like_mut) else {
201+
continue;
202+
};
203+
204+
updated |= update_dependency_version_in_dependencies(dependencies, crate_name, dependency);
205+
}
206+
207+
let Some(targets) = table.get_mut("target").and_then(Item::as_table_like_mut) else {
208+
return updated;
209+
};
210+
211+
for (_, target) in targets.iter_mut() {
212+
let Some(target) = target.as_table_like_mut() else {
213+
continue;
214+
};
215+
updated |= update_dependency_version_in_table(target, crate_name, dependency);
216+
}
217+
218+
updated
219+
}
220+
221+
fn update_dependency_version_in_dependencies(
222+
dependencies: &mut dyn TableLike,
223+
crate_name: &str,
224+
dependency: &Package,
225+
) -> bool {
226+
let Some(entry) = dependencies.get_mut(crate_name) else {
227+
return false;
228+
};
229+
let Some(entry) = entry.as_table_like_mut() else {
230+
return false;
231+
};
232+
let Some("../../core") = entry.get("path").and_then(Item::as_str) else {
233+
return false;
234+
};
235+
let Some(value) = entry.get_mut("version") else {
236+
return false;
237+
};
238+
239+
let old_version = match value.as_str() {
240+
Some(version) => match Version::parse(version) {
241+
Ok(version) => version,
242+
Err(_) => return false,
243+
},
244+
None => panic!("missing dependency version for crate: {crate_name}"),
245+
};
246+
247+
if old_version == dependency.version {
248+
return false;
249+
}
250+
251+
*value = toml_edit::value(dependency.version.to_string());
252+
println!(
253+
"updating dependency version for crate: {} from {} to {}",
254+
crate_name, old_version, dependency.version
255+
);
256+
true
257+
}
258+
259+
impl Package {
260+
fn crate_name(&self) -> Option<&'static str> {
261+
match self.name.as_str() {
262+
"core" => Some("opendal"),
263+
_ => None,
264+
}
136265
}
137266
}
138267

@@ -193,3 +322,126 @@ fn update_nodejs_version(path: &Path, version: &Version) -> bool {
193322

194323
updated
195324
}
325+
326+
#[cfg(test)]
327+
mod tests {
328+
use super::*;
329+
330+
fn temp_test_dir(name: &str) -> PathBuf {
331+
let nanos = std::time::SystemTime::now()
332+
.duration_since(std::time::UNIX_EPOCH)
333+
.unwrap()
334+
.as_nanos();
335+
std::env::temp_dir().join(format!("odev-package-{name}-{nanos}"))
336+
}
337+
338+
#[test]
339+
fn parquet_release_version_matches_manifest() {
340+
let parquet = all_packages()
341+
.into_iter()
342+
.find(|package| package.name() == "integrations/parquet")
343+
.unwrap();
344+
345+
assert_eq!(parquet.version, Version::parse("0.8.0").unwrap());
346+
}
347+
348+
#[test]
349+
fn update_manifest_version_supports_workspace_package_version() {
350+
let mut manifest = DocumentMut::from_str(
351+
r#"
352+
[workspace.package]
353+
version = "0.55.0"
354+
355+
[package]
356+
name = "opendal"
357+
version = { workspace = true }
358+
"#,
359+
)
360+
.unwrap();
361+
362+
let updated = update_manifest_version(
363+
&mut manifest,
364+
&Version::parse("0.56.0").unwrap(),
365+
Path::new("core/Cargo.toml"),
366+
);
367+
368+
assert!(updated);
369+
assert_eq!(
370+
manifest["workspace"]["package"]["version"].as_str(),
371+
Some("0.56.0")
372+
);
373+
assert!(!manifest["package"]["version"].is_str());
374+
}
375+
376+
#[test]
377+
fn update_dependency_version_only_touches_release_managed_core_constraints() {
378+
let dir = temp_test_dir("dependency-sync");
379+
std::fs::create_dir_all(&dir).unwrap();
380+
381+
let manifest_path = dir.join("Cargo.toml");
382+
std::fs::write(
383+
&manifest_path,
384+
r#"[package]
385+
name = "demo"
386+
version = "0.8.0"
387+
388+
[dependencies]
389+
opendal = { version = "0.55.0", path = "../../core" }
390+
serde = "1"
391+
392+
[dev-dependencies]
393+
opendal = { version = "0.55.0", path = "../../core", features = ["services-memory"] }
394+
395+
[build-dependencies]
396+
opendal = { version = ">=0", path = "../../core" }
397+
398+
[target.'cfg(unix)'.dependencies]
399+
opendal = { version = "0.55.0", path = "../../core" }
400+
401+
[target.'cfg(windows)'.dependencies]
402+
opendal = { version = "0.55.0", path = "../core" }
403+
"#,
404+
)
405+
.unwrap();
406+
407+
let dependency = Package {
408+
name: "core".to_string(),
409+
path: PathBuf::from("core"),
410+
version: Version::parse("0.56.0").unwrap(),
411+
dependencies: vec![],
412+
};
413+
414+
let updated = update_cargo_version(
415+
dir.as_path(),
416+
&Version::parse("0.8.0").unwrap(),
417+
&[dependency],
418+
);
419+
assert!(updated);
420+
421+
let manifest = std::fs::read_to_string(&manifest_path).unwrap();
422+
let manifest = DocumentMut::from_str(&manifest).unwrap();
423+
424+
assert_eq!(
425+
manifest["dependencies"]["opendal"]["version"].as_str(),
426+
Some("0.56.0")
427+
);
428+
assert_eq!(
429+
manifest["dev-dependencies"]["opendal"]["version"].as_str(),
430+
Some("0.56.0")
431+
);
432+
assert_eq!(
433+
manifest["target"]["cfg(unix)"]["dependencies"]["opendal"]["version"].as_str(),
434+
Some("0.56.0")
435+
);
436+
assert_eq!(
437+
manifest["build-dependencies"]["opendal"]["version"].as_str(),
438+
Some(">=0")
439+
);
440+
assert_eq!(
441+
manifest["target"]["cfg(windows)"]["dependencies"]["opendal"]["version"].as_str(),
442+
Some("0.55.0")
443+
);
444+
445+
std::fs::remove_dir_all(dir).unwrap();
446+
}
447+
}

0 commit comments

Comments
 (0)