feat(cli): enhance iOS bundle version formatting (#13218)

* feat(cli): enhance iOS bundle version formatting

follow-up for #13030 and https://github.com/tauri-apps/cargo-mobile2/pull/450

the bundle version validation has been updated, now it can actually handle one or two integers (e.g. `100` or `10.7`) instead of just full triple semver strings (e.g. `10.7.1`).

* lint
This commit is contained in:
Lucas Fernandes Nogueira
2025-04-12 20:51:56 -03:00
committed by GitHub
parent b072e2b296
commit 3752fed282
5 changed files with 103 additions and 67 deletions

18
Cargo.lock generated
View File

@@ -1062,9 +1062,9 @@ dependencies = [
[[package]]
name = "cargo-mobile2"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9faa9fae5ccf60d68e6b766293be17bbce2de0aece38886f2eb1ac8da8718942"
checksum = "24b5acda005352ad50a3e58c8777781732d6ac1e8a82ab90d5ffd70b69c665f1"
dependencies = [
"colored",
"core-foundation 0.10.0",
@@ -1355,7 +1355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -2347,7 +2347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -5792,7 +5792,7 @@ dependencies = [
"aes-gcm",
"aes-kw",
"argon2",
"base64 0.21.7",
"base64 0.22.1",
"bitfield",
"block-padding",
"blowfish",
@@ -6372,7 +6372,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -7057,7 +7057,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -8917,7 +8917,7 @@ dependencies = [
"getrandom 0.2.15",
"once_cell",
"rustix 0.38.43",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -10178,7 +10178,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]

View File

@@ -36,7 +36,7 @@ name = "cargo-tauri"
path = "src/main.rs"
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"windows\", target_os = \"macos\"))".dependencies]
cargo-mobile2 = { version = "0.18", default-features = false }
cargo-mobile2 = { version = "0.19", default-features = false }
[dependencies]
jsonrpsee = { version = "0.24", features = ["server"] }

View File

@@ -119,3 +119,23 @@ pub fn run_hook(
Ok(())
}
#[cfg(target_os = "macos")]
pub fn strip_semver_prerelease_tag(version: &mut semver::Version) -> crate::Result<()> {
if !version.pre.is_empty() {
if let Some((_prerelease_tag, number)) = version.pre.as_str().to_string().split_once('.') {
version.pre = semver::Prerelease::EMPTY;
version.build = semver::BuildMetadata::new(&format!(
"{prefix}{number}",
prefix = if version.build.is_empty() {
"".to_string()
} else {
format!(".{}", version.build.as_str())
}
))
.with_context(|| format!("bundle version {number:?} prerelease is invalid"))?;
}
}
Ok(())
}

View File

@@ -14,7 +14,7 @@ use crate::{
config::{get as get_tauri_config, ConfigHandle},
flock,
},
interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions},
interface::{AppInterface, Interface, Options as InterfaceOptions},
mobile::{write_options, CliOptions},
ConfigValue, Result,
};
@@ -36,7 +36,6 @@ use std::{
env::{set_current_dir, var, var_os},
fs,
path::PathBuf,
str::FromStr,
};
#[derive(Debug, Clone, Parser)]
@@ -183,36 +182,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;
let mut plist = plist::Dictionary::new();
{
let tauri_config_guard = tauri_config.lock().unwrap();
let tauri_config_ = tauri_config_guard.as_ref().unwrap();
let app_version = tauri_config_
.version
.clone()
.unwrap_or_else(|| interface.app_settings().get_package_settings().version);
let mut version = semver::Version::from_str(&app_version)
.with_context(|| format!("failed to parse {app_version:?} as a semver string"))?;
if !version.pre.is_empty() {
log::info!(
"CFBundleShortVersionString cannot have prerelease identifier; stripping {}",
version.pre.as_str()
);
version.pre = semver::Prerelease::EMPTY;
}
if !version.build.is_empty() {
log::info!(
"CFBundleShortVersionString cannot have build number; stripping {}",
version.build.as_str()
);
version.build = semver::BuildMetadata::EMPTY;
}
plist.insert(
"CFBundleShortVersionString".into(),
version.to_string().into(),
);
};
plist.insert(
"CFBundleShortVersionString".into(),
config.bundle_version_short().into(),
);
let info_plist_path = config
.project_dir()
@@ -338,9 +311,10 @@ fn run_build(
&detect_target_ok,
env,
|target: &Target| -> Result<()> {
let mut app_version = config.bundle_version().clone();
let mut app_version = config.bundle_version().to_string();
if let Some(build_number) = options.build_number {
app_version.push_extra(build_number);
app_version.push('.');
app_version.push_str(&build_number.to_string());
}
let credentials = auth_credentials_from_env()?;

View File

@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use anyhow::Context;
use cargo_mobile2::{
apple::{
config::{
@@ -31,7 +30,7 @@ use crate::{
helpers::{
app_paths::tauri_dir,
config::{BundleResources, Config as TauriConfig, ConfigHandle},
pbxproj,
pbxproj, strip_semver_prerelease_tag,
},
Result,
};
@@ -130,30 +129,72 @@ pub fn get_config(
.clone()
.or_else(|| tauri_config.version.clone())
{
let mut version = semver::Version::from_str(&bundle_version)
.with_context(|| format!("failed to parse {bundle_version:?} as a semver string"))?;
if !version.pre.is_empty() {
if let Some((_prerelease_tag, number)) = version.pre.as_str().to_string().split_once('.') {
version.pre = semver::Prerelease::EMPTY;
if version.build.is_empty() {
version.build = semver::BuildMetadata::new(number)
.with_context(|| format!("bundle version {number:?} prerelease is invalid"))?;
} else {
anyhow::bail!("bundle version {bundle_version:?} is invalid, it cannot have both prerelease and build metadata");
}
// if it's a semver string, we must strip the prerelease tag
if let Ok(mut version) = semver::Version::from_str(&bundle_version) {
if !version.pre.is_empty() {
log::warn!("CFBundleVersion cannot have prerelease tag; stripping from {bundle_version}");
strip_semver_prerelease_tag(&mut version)?;
}
// correctly serialize version - cannot contain `+` as build metadata separator
Some(format!(
"{}.{}.{}{}",
version.major,
version.minor,
version.patch,
if version.build.is_empty() {
"".to_string()
} else {
format!(".{}", version.build.as_str())
}
))
} else {
// let it go as is - cargo-mobile2 will validate it
Some(bundle_version)
}
} else {
None
};
let full_bundle_version_short = if let Some(app_version) = &tauri_config.version {
if let Ok(mut version) = semver::Version::from_str(app_version) {
if !version.pre.is_empty() {
log::warn!(
"CFBundleShortVersionString cannot have prerelease tag; stripping from {app_version}"
);
strip_semver_prerelease_tag(&mut version)?;
}
// correctly serialize version - cannot contain `+` as build metadata separator
Some(format!(
"{}.{}.{}{}",
version.major,
version.minor,
version.patch,
if version.build.is_empty() {
"".to_string()
} else {
format!(".{}", version.build.as_str())
}
))
} else {
// let it go as is - cargo-mobile2 will validate it
Some(app_version.clone())
}
} else {
bundle_version.clone()
};
let bundle_version_short = if let Some(full_version) = full_bundle_version_short.as_deref() {
let mut s = full_version.split('.');
let short_version = format!(
"{}.{}.{}",
s.next().unwrap_or("0"),
s.next().unwrap_or("0"),
s.next().unwrap_or("0")
);
if short_version != full_version {
log::warn!("{full_version:?} is not a valid CFBundleShortVersionString since it must contain exactly three dot separated integers; setting it to {short_version} instead");
}
let maybe_build_number = if version.build.is_empty() {
"".to_string()
} else {
format!(".{}", version.build.as_str())
};
Some(format!(
"{}.{}.{}{}",
version.major, version.minor, version.patch, maybe_build_number
))
Some(short_version)
} else {
None
};
@@ -178,6 +219,7 @@ pub fn get_config(
}),
ios_features: ios_options.features.clone(),
bundle_version,
bundle_version_short,
ios_version: Some(tauri_config.bundle.ios.minimum_system_version.clone()),
..Default::default()
};