//! Publish configuration — parsed from the `[publish]` section of `manifest.el`. /// App Store Connect / TestFlight configuration. #[derive(Debug, Clone)] pub struct AppleConfig { pub account: String, pub team_id: String, pub bundle_id: String, pub category: String, } impl AppleConfig { pub fn new( account: impl Into, team_id: impl Into, bundle_id: impl Into, ) -> Self { Self { account: account.into(), team_id: team_id.into(), bundle_id: bundle_id.into(), category: "productivity".into(), } } pub fn with_category(mut self, category: impl Into) -> Self { self.category = category.into(); self } } /// Google Play Developer API configuration. #[derive(Debug, Clone)] pub struct GoogleConfig { pub service_account_path: String, pub package_name: String, /// Which track to publish to: "internal" | "alpha" | "beta" | "production" pub track: String, } impl GoogleConfig { pub fn new( service_account_path: impl Into, package_name: impl Into, ) -> Self { Self { service_account_path: service_account_path.into(), package_name: package_name.into(), track: "internal".into(), } } pub fn with_track(mut self, track: impl Into) -> Self { self.track = track.into(); self } } /// Staged rollout configuration. #[derive(Debug, Clone)] pub struct RolloutConfig { /// Initial rollout percentage (0-100). pub initial_percent: u8, /// Automatically advance rollout after `advance_after_hours` hours. pub auto_advance: bool, pub advance_after_hours: u64, /// Halt rollout if crash rate exceeds this fraction (0.0 - 1.0). pub max_crash_rate: f64, } impl Default for RolloutConfig { fn default() -> Self { Self { initial_percent: 100, auto_advance: false, advance_after_hours: 24, max_crash_rate: 0.01, } } } impl RolloutConfig { pub fn new(initial_percent: u8) -> Self { Self { initial_percent, ..Default::default() } } pub fn with_auto_advance(mut self, hours: u64) -> Self { self.auto_advance = true; self.advance_after_hours = hours; self } pub fn with_max_crash_rate(mut self, rate: f64) -> Self { self.max_crash_rate = rate; self } } /// The complete publish configuration. #[derive(Debug, Clone)] pub struct PublishConfig { pub version: String, pub build_number: u32, pub apple: Option, pub google: Option, pub rollout: Option, /// Directory with store metadata (title.txt, description.txt, etc.) pub metadata_dir: String, pub screenshot_targets: Vec, } impl PublishConfig { pub fn new(version: impl Into, build_number: u32) -> Self { Self { version: version.into(), build_number, apple: None, google: None, rollout: None, metadata_dir: "./store".into(), screenshot_targets: Vec::new(), } } pub fn with_apple(mut self, apple: AppleConfig) -> Self { self.apple = Some(apple); self } pub fn with_google(mut self, google: GoogleConfig) -> Self { self.google = Some(google); self } pub fn with_rollout(mut self, rollout: RolloutConfig) -> Self { self.rollout = Some(rollout); self } pub fn with_screenshot_targets(mut self, targets: Vec>) -> Self { self.screenshot_targets = targets.into_iter().map(|t| t.into()).collect(); self } }