mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:37:09 +00:00
feat: add option to not wait on notarization to finish (#13521)
* feat: add option to not wait on notarization to finish * cli arg istead of config * changefile * fix serde --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
parent
f0dcf9637c
commit
a9ec12843a
7
.changes/feat-skip-stapling.md
Normal file
7
.changes/feat-skip-stapling.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
tauri-macos-sign: 'minor:feat'
|
||||
tauri-bundler: 'minor:feat'
|
||||
tauri-cli: 'minor:feat'
|
||||
---
|
||||
|
||||
Added a `--skip-stapling` option to make `tauri build|bundle` _not_ wait for notarization to finish on macOS.
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
use super::{
|
||||
icon::create_icns_file,
|
||||
sign::{notarize, notarize_auth, sign, NotarizeAuthError, SignTarget},
|
||||
sign::{notarize, notarize_auth, notarize_without_stapling, sign, NotarizeAuthError, SignTarget},
|
||||
};
|
||||
use crate::{
|
||||
utils::{fs_utils, CommandExt},
|
||||
@ -121,7 +121,11 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
|
||||
// notarization is required for distribution
|
||||
match notarize_auth() {
|
||||
Ok(auth) => {
|
||||
notarize(&keychain, app_bundle_path.clone(), &auth)?;
|
||||
if settings.macos().skip_stapling {
|
||||
notarize_without_stapling(&keychain, app_bundle_path.clone(), &auth)?;
|
||||
} else {
|
||||
notarize(&keychain, app_bundle_path.clone(), &auth)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if matches!(e, NotarizeAuthError::MissingTeamId) {
|
||||
|
||||
@ -71,6 +71,15 @@ pub fn notarize(
|
||||
tauri_macos_sign::notarize(keychain, &app_bundle_path, credentials).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn notarize_without_stapling(
|
||||
keychain: &tauri_macos_sign::Keychain,
|
||||
app_bundle_path: PathBuf,
|
||||
credentials: &tauri_macos_sign::AppleNotarizationCredentials,
|
||||
) -> crate::Result<()> {
|
||||
tauri_macos_sign::notarize_without_stapling(keychain, &app_bundle_path, credentials)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum NotarizeAuthError {
|
||||
#[error(
|
||||
|
||||
@ -346,6 +346,15 @@ pub struct MacOsSettings {
|
||||
pub exception_domain: Option<String>,
|
||||
/// Code signing identity.
|
||||
pub signing_identity: Option<String>,
|
||||
/// Whether to wait for notarization to finish and `staple` the ticket onto the app.
|
||||
///
|
||||
/// Gatekeeper will look for stapled tickets to tell whether your app was notarized without
|
||||
/// reaching out to Apple's servers which is helpful in offline environments.
|
||||
///
|
||||
/// Enabling this option will also result in `tauri build` not waiting for notarization to finish
|
||||
/// which is helpful for the very first time your app is notarized as this can take multiple hours.
|
||||
/// On subsequent runs, it's recommended to disable this setting again.
|
||||
pub skip_stapling: bool,
|
||||
/// Preserve the hardened runtime version flag, see <https://developer.apple.com/documentation/security/hardened_runtime>
|
||||
///
|
||||
/// Settings this to `false` is useful when using an ad-hoc signature, making it less strict.
|
||||
|
||||
@ -60,6 +60,16 @@ pub struct Options {
|
||||
/// Skip prompting for values
|
||||
#[clap(long, env = "CI")]
|
||||
pub ci: bool,
|
||||
/// Whether to wait for notarization to finish and `staple` the ticket onto the app.
|
||||
///
|
||||
/// Gatekeeper will look for stapled tickets to tell whether your app was notarized without
|
||||
/// reaching out to Apple's servers which is helpful in offline environments.
|
||||
///
|
||||
/// Enabling this option will also result in `tauri build` not waiting for notarization to finish
|
||||
/// which is helpful for the very first time your app is notarized as this can take multiple hours.
|
||||
/// On subsequent runs, it's recommended to disable this setting again.
|
||||
#[clap(long)]
|
||||
pub skip_stapling: bool,
|
||||
}
|
||||
|
||||
pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
|
||||
|
||||
@ -82,6 +82,16 @@ pub struct Options {
|
||||
/// Skip prompting for values
|
||||
#[clap(long, env = "CI")]
|
||||
pub ci: bool,
|
||||
/// Whether to wait for notarization to finish and `staple` the ticket onto the app.
|
||||
///
|
||||
/// Gatekeeper will look for stapled tickets to tell whether your app was notarized without
|
||||
/// reaching out to Apple's servers which is helpful in offline environments.
|
||||
///
|
||||
/// Enabling this option will also result in `tauri build` not waiting for notarization to finish
|
||||
/// which is helpful for the very first time your app is notarized as this can take multiple hours.
|
||||
/// On subsequent runs, it's recommended to disable this setting again.
|
||||
#[clap(long)]
|
||||
pub skip_stapling: bool,
|
||||
}
|
||||
|
||||
impl From<crate::build::Options> for Options {
|
||||
@ -93,6 +103,7 @@ impl From<crate::build::Options> for Options {
|
||||
debug: value.debug,
|
||||
ci: value.ci,
|
||||
config: value.config,
|
||||
skip_stapling: value.skip_stapling,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ pub trait AppSettings {
|
||||
fn get_package_settings(&self) -> tauri_bundler::PackageSettings;
|
||||
fn get_bundle_settings(
|
||||
&self,
|
||||
options: &Options,
|
||||
config: &Config,
|
||||
features: &[String],
|
||||
) -> crate::Result<tauri_bundler::BundleSettings>;
|
||||
@ -52,7 +53,7 @@ pub trait AppSettings {
|
||||
enabled_features.push("default".into());
|
||||
}
|
||||
|
||||
let target: String = if let Some(target) = options.target {
|
||||
let target: String = if let Some(target) = options.target.clone() {
|
||||
target
|
||||
} else {
|
||||
tauri_utils::platform::target_triple()?
|
||||
@ -66,7 +67,7 @@ pub trait AppSettings {
|
||||
|
||||
let mut settings_builder = SettingsBuilder::new()
|
||||
.package_settings(self.get_package_settings())
|
||||
.bundle_settings(self.get_bundle_settings(config, &enabled_features)?)
|
||||
.bundle_settings(self.get_bundle_settings(&options, config, &enabled_features)?)
|
||||
.binaries(bins)
|
||||
.project_out_directory(out_dir)
|
||||
.target(target)
|
||||
|
||||
@ -55,6 +55,7 @@ pub struct Options {
|
||||
pub args: Vec<String>,
|
||||
pub config: Vec<ConfigValue>,
|
||||
pub no_watch: bool,
|
||||
pub skip_stapling: bool,
|
||||
pub additional_watch_folders: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
@ -68,6 +69,7 @@ impl From<crate::build::Options> for Options {
|
||||
args: options.args,
|
||||
config: options.config,
|
||||
no_watch: true,
|
||||
skip_stapling: options.skip_stapling,
|
||||
additional_watch_folders: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -81,6 +83,7 @@ impl From<crate::bundle::Options> for Options {
|
||||
target: options.target,
|
||||
features: options.features,
|
||||
no_watch: true,
|
||||
skip_stapling: options.skip_stapling,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@ -96,6 +99,7 @@ impl From<crate::dev::Options> for Options {
|
||||
args: options.args,
|
||||
config: options.config,
|
||||
no_watch: options.no_watch,
|
||||
skip_stapling: false,
|
||||
additional_watch_folders: options.additional_watch_folders,
|
||||
}
|
||||
}
|
||||
@ -813,6 +817,7 @@ impl AppSettings for RustAppSettings {
|
||||
|
||||
fn get_bundle_settings(
|
||||
&self,
|
||||
options: &Options,
|
||||
config: &Config,
|
||||
features: &[String],
|
||||
) -> crate::Result<BundleSettings> {
|
||||
@ -851,6 +856,8 @@ impl AppSettings for RustAppSettings {
|
||||
arch64bits,
|
||||
)?;
|
||||
|
||||
settings.macos.skip_stapling = options.skip_stapling;
|
||||
|
||||
if let Some(plugin_config) = config
|
||||
.plugins
|
||||
.0
|
||||
@ -1466,6 +1473,7 @@ fn tauri_config_to_bundle_settings(
|
||||
minimum_system_version: config.macos.minimum_system_version,
|
||||
exception_domain: config.macos.exception_domain,
|
||||
signing_identity,
|
||||
skip_stapling: false,
|
||||
hardened_runtime: config.macos.hardened_runtime,
|
||||
provider_short_name,
|
||||
entitlements: config.macos.entitlements,
|
||||
|
||||
@ -92,6 +92,7 @@ impl From<Options> for BuildOptions {
|
||||
config: options.config,
|
||||
args: options.args,
|
||||
ci: options.ci,
|
||||
skip_stapling: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +132,7 @@ impl From<Options> for BuildOptions {
|
||||
config: options.config,
|
||||
args: options.args,
|
||||
ci: options.ci,
|
||||
skip_stapling: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +57,8 @@ pub enum AppleNotarizationCredentials {
|
||||
#[derive(Deserialize)]
|
||||
struct NotarytoolSubmitOutput {
|
||||
id: String,
|
||||
status: String,
|
||||
#[serde(default)]
|
||||
status: Option<String>,
|
||||
message: String,
|
||||
}
|
||||
|
||||
@ -65,6 +66,23 @@ pub fn notarize(
|
||||
keychain: &Keychain,
|
||||
app_bundle_path: &Path,
|
||||
auth: &AppleNotarizationCredentials,
|
||||
) -> Result<()> {
|
||||
notarize_inner(keychain, app_bundle_path, auth, true)
|
||||
}
|
||||
|
||||
pub fn notarize_without_stapling(
|
||||
keychain: &Keychain,
|
||||
app_bundle_path: &Path,
|
||||
auth: &AppleNotarizationCredentials,
|
||||
) -> Result<()> {
|
||||
notarize_inner(keychain, app_bundle_path, auth, false)
|
||||
}
|
||||
|
||||
fn notarize_inner(
|
||||
keychain: &Keychain,
|
||||
app_bundle_path: &Path,
|
||||
auth: &AppleNotarizationCredentials,
|
||||
wait: bool,
|
||||
) -> Result<()> {
|
||||
let bundle_stem = app_bundle_path
|
||||
.file_stem()
|
||||
@ -97,16 +115,19 @@ pub fn notarize(
|
||||
// sign the zip file
|
||||
keychain.sign(&zip_path, None, false)?;
|
||||
|
||||
let notarize_args = vec![
|
||||
let mut notarize_args = vec![
|
||||
"notarytool",
|
||||
"submit",
|
||||
zip_path
|
||||
.to_str()
|
||||
.expect("failed to convert zip_path to string"),
|
||||
"--wait",
|
||||
"--output-format",
|
||||
"json",
|
||||
];
|
||||
if wait {
|
||||
notarize_args.push("--wait");
|
||||
}
|
||||
let notarize_args = notarize_args;
|
||||
|
||||
println!("Notarizing {}", app_bundle_path.display());
|
||||
|
||||
@ -126,12 +147,28 @@ pub fn notarize(
|
||||
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||
if let Ok(submit_output) = serde_json::from_str::<NotarytoolSubmitOutput>(&output_str) {
|
||||
let log_message = format!(
|
||||
"Finished with status {} for id {} ({})",
|
||||
submit_output.status, submit_output.id, submit_output.message
|
||||
"{} with status {} for id {} ({})",
|
||||
if wait { "Finished" } else { "Submitted" },
|
||||
submit_output.status.as_deref().unwrap_or("Pending"),
|
||||
submit_output.id,
|
||||
submit_output.message
|
||||
);
|
||||
if submit_output.status == "Accepted" {
|
||||
// status is empty when not waiting for the notarization to finish
|
||||
if submit_output.status.map_or(!wait, |s| s == "Accepted") {
|
||||
println!("Notarizing {log_message}");
|
||||
staple_app(app_bundle_path.to_path_buf())?;
|
||||
|
||||
if wait {
|
||||
println!("Stapling app...");
|
||||
staple_app(app_bundle_path.to_path_buf())?;
|
||||
} else {
|
||||
println!("Not waiting for notarization to finish.");
|
||||
println!("You can use `xcrun notarytool log` to check the notarization progress.");
|
||||
println!(
|
||||
"When it's done you can optionally staple your app via `xcrun stapler staple {}`",
|
||||
app_bundle_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else if let Ok(output) = Command::new("xcrun")
|
||||
.args(["notarytool", "log"])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user