From b3f2d12b89daefe528e562b93871db62f77973b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Andr=C3=A9?= Date: Mon, 27 Apr 2026 09:20:47 +0200 Subject: [PATCH] fix(tauri-build): preserve numeric semver build metadata in Windows FILEVERSION (#15289) * fix(tauri-build): preserve numeric semver build metadata in Windows FILEVERSION * refactor(tauri-build): clarify PRODUCTVERSION naming * refactor(tauri-build): align fixed Windows version fields * refactor(tauri-build): rename Windows version helper * style(tauri-build): move winres helper near tests --- .../windows-fileversion-build-metadata.md | 5 ++ crates/tauri-build/src/lib.rs | 53 ++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 .changes/windows-fileversion-build-metadata.md diff --git a/.changes/windows-fileversion-build-metadata.md b/.changes/windows-fileversion-build-metadata.md new file mode 100644 index 000000000000..a3fdc2007f08 --- /dev/null +++ b/.changes/windows-fileversion-build-metadata.md @@ -0,0 +1,5 @@ +--- +"tauri-build": "patch:enhance" +--- + +Preserve a numeric semver build identifier such as `1.2.3+42` in the 4th segment of the Windows `FILEVERSION` fixed field when it fits in the Windows version format. diff --git a/crates/tauri-build/src/lib.rs b/crates/tauri-build/src/lib.rs index 7ce48744f0b6..6c171a3005f9 100644 --- a/crates/tauri-build/src/lib.rs +++ b/crates/tauri-build/src/lib.rs @@ -631,7 +631,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { if let Some(version_str) = &config.version { if let Ok(v) = Version::parse(version_str) { - let version = (v.major << 48) | (v.minor << 32) | (v.patch << 16); + let version = to_winres_version(&v); res.set_version_info(VersionInfo::FILEVERSION, version); res.set_version_info(VersionInfo::PRODUCTVERSION, version); res.set("FileVersion", version_str); @@ -719,3 +719,54 @@ pub fn try_build(attributes: Attributes) -> Result<()> { Ok(()) } + +fn to_winres_version(v: &semver::Version) -> u64 { + let build = v.build.parse::().map(u64::from).unwrap_or(0); + + (v.major << 48) | (v.minor << 32) | (v.patch << 16) | build +} + +#[cfg(test)] +mod tests { + use semver::Version; + + #[test] + fn version_uses_numeric_build_metadata() { + let version = Version::parse("1.2.3+42").unwrap(); + + assert_eq!( + crate::to_winres_version(&version), + (1 << 48) | (2 << 32) | (3 << 16) | 42 + ); + } + + #[test] + fn version_ignores_non_numeric_composite_build_metadata() { + let version = Version::parse("1.2.3+42.sha").unwrap(); + + assert_eq!( + crate::to_winres_version(&version), + (1 << 48) | (2 << 32) | (3 << 16) + ); + } + + #[test] + fn version_ignores_non_numeric_build_metadata() { + let version = Version::parse("1.2.3+abc").unwrap(); + + assert_eq!( + crate::to_winres_version(&version), + (1 << 48) | (2 << 32) | (3 << 16) + ); + } + + #[test] + fn version_ignores_build_metadata_that_does_not_fit_in_u16() { + let version = Version::parse("1.2.3+70000").unwrap(); + + assert_eq!( + crate::to_winres_version(&version), + (1 << 48) | (2 << 32) | (3 << 16) + ); + } +}