feat(bundler): add wix > version option (#11388)

* feat(bundler): add `wix > version` option

closes #11253

* Update crates/tauri-bundler/src/bundle/settings.rs

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
This commit is contained in:
Amr Bashir 2024-10-17 18:37:15 +03:00 committed by GitHub
parent bd1b2a1e85
commit c8f55b615d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 107 additions and 7 deletions

View File

@ -0,0 +1,6 @@
---
"tauri-bundler": "patch:feat"
---
Add `bundler > windows > wix > version` to manually specify a wix-compatible version.

View File

@ -351,6 +351,15 @@ impl Default for WixLanguage {
/// Settings specific to the WiX implementation.
#[derive(Clone, Debug, Default)]
pub struct WixSettings {
/// MSI installer version in the format `major.minor.patch.build` (build is optional).
///
/// Because a valid version is required for MSI installer, it will be derived from [`PackageSettings::version`] if this field is not set.
///
/// The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.
/// The third and fourth fields have a maximum value of 65,535.
///
/// See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.
pub version: Option<String>,
/// A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,
/// otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.
///

View File

@ -282,19 +282,37 @@ fn clear_env_for_wix(cmd: &mut Command) {
}
}
// WiX requires versions to be numeric only in a `major.minor.patch.build` format
pub fn convert_version(version_str: &str) -> anyhow::Result<String> {
let version = semver::Version::parse(version_str).context("invalid app version")?;
if version.major > 255 {
fn validate_wix_version(version_str: &str) -> anyhow::Result<()> {
let components = version_str
.split('.')
.flat_map(|c| c.parse::<u64>().ok())
.collect::<Vec<_>>();
anyhow::ensure!(
components.len() >= 3,
"app wix version should be in the format major.minor.patch.build (build is optional)"
);
if components[0] > 255 {
bail!("app version major number cannot be greater than 255");
}
if version.minor > 255 {
if components[1] > 255 {
bail!("app version minor number cannot be greater than 255");
}
if version.patch > 65535 {
if components[2] > 65535 {
bail!("app version patch number cannot be greater than 65535");
}
if components.len() == 4 && components[3] > 65535 {
bail!("app version build number cannot be greater than 65535");
}
Ok(())
}
// WiX requires versions to be numeric only in a `major.minor.patch.build` format
fn convert_version(version_str: &str) -> anyhow::Result<String> {
let version = semver::Version::parse(version_str).context("invalid app version")?;
if !version.build.is_empty() {
let build = version.build.parse::<u64>();
if build.map(|b| b <= 65535).unwrap_or_default() {
@ -433,7 +451,18 @@ pub fn build_wix_app_installer(
}
};
let app_version = convert_version(settings.version_string())?;
let app_version = if let Some(version) = settings
.windows()
.wix
.as_ref()
.and_then(|wix| wix.version.clone())
{
version
} else {
convert_version(settings.version_string())?
};
validate_wix_version(&app_version)?;
// target only supports x64.
log::info!("Target: {}", arch);
@ -1056,3 +1085,35 @@ fn generate_resource_data(settings: &Settings) -> crate::Result<ResourceMap> {
Ok(resources)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validates_wix_version() {
assert!(validate_wix_version("1.1.1").is_ok());
assert!(validate_wix_version("1.1.1.1").is_ok());
assert!(validate_wix_version("255.1.1.1").is_ok());
assert!(validate_wix_version("1.255.1.1").is_ok());
assert!(validate_wix_version("1.1.65535.1").is_ok());
assert!(validate_wix_version("1.1.1.65535").is_ok());
assert!(validate_wix_version("256.1.1.1").is_err());
assert!(validate_wix_version("1.256.1.1").is_err());
assert!(validate_wix_version("1.1.65536.1").is_err());
assert!(validate_wix_version("1.1.1.65536").is_err());
}
#[test]
fn converts_version_to_wix() {
assert_eq!(convert_version("1.1.2").unwrap(), "1.1.2");
assert_eq!(convert_version("1.1.2-4").unwrap(), "1.1.2.4");
assert_eq!(convert_version("1.1.2-65535").unwrap(), "1.1.2.65535");
assert_eq!(convert_version("1.1.2+2").unwrap(), "1.1.2.2");
assert!(convert_version("1.1.2-alpha").is_err());
assert!(convert_version("1.1.2-alpha.4").is_err());
assert!(convert_version("1.1.2+asd.3").is_err());
}
}

View File

@ -2170,6 +2170,13 @@
"description": "Configuration for the MSI bundle using WiX.\n\n See more: <https://v2.tauri.app/reference/config/#wixconfig>",
"type": "object",
"properties": {
"version": {
"description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and foruth fields have a maximum value of 65,535.\n\n See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.",
"type": [
"string",
"null"
]
},
"upgradeCode": {
"description": "A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,\n otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.\n\n By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.\n You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.\n\n It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code\n whenever you want to change your product name.",
"type": [

View File

@ -62,6 +62,7 @@ pub type ConfigHandle = Arc<Mutex<Option<ConfigMetadata>>>;
pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings {
tauri_bundler::WixSettings {
version: config.version,
upgrade_code: config.upgrade_code,
language: tauri_bundler::WixLanguage(match config.language {
WixLanguage::One(lang) => vec![(lang, Default::default())],

View File

@ -2170,6 +2170,13 @@
"description": "Configuration for the MSI bundle using WiX.\n\n See more: <https://v2.tauri.app/reference/config/#wixconfig>",
"type": "object",
"properties": {
"version": {
"description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and foruth fields have a maximum value of 65,535.\n\n See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.",
"type": [
"string",
"null"
]
},
"upgradeCode": {
"description": "A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,\n otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.\n\n By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.\n You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.\n\n It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code\n whenever you want to change your product name.",
"type": [

View File

@ -658,6 +658,15 @@ impl Default for WixLanguage {
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct WixConfig {
/// MSI installer version in the format `major.minor.patch.build` (build is optional).
///
/// Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.
///
/// The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.
/// The third and foruth fields have a maximum value of 65,535.
///
/// See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.
pub version: Option<String>,
/// A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,
/// otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.
///