use crate::{ExternalBindings, ManagementConfig, StackSettings};
use bon::Builder;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::{is_false, ComputeBackend, DomainMetadata, EnvironmentVariablesSnapshot};
#[derive(Debug, Clone, Serialize, Deserialize, Builder)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct DeploymentConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deployment_name: Option<String>,
#[serde(default)]
pub stack_settings: StackSettings,
#[serde(skip_serializing_if = "Option::is_none")]
pub management_config: Option<ManagementConfig>,
pub environment_variables: EnvironmentVariablesSnapshot,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
#[builder(default)]
pub input_values: HashMap<String, serde_json::Value>,
#[serde(default, skip_serializing_if = "is_false")]
pub allow_frozen_changes: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub compute_backend: Option<ComputeBackend>,
#[serde(default)]
pub external_bindings: ExternalBindings,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub base_platform: Option<crate::Platform>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label_domain: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub observe_label_selector: Option<String>,
#[serde(default)]
#[builder(default)]
pub observe_all_namespaces: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub public_endpoints: Option<HashMap<String, HashMap<String, String>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub domain_metadata: Option<DomainMetadata>,
#[serde(skip_serializing_if = "Option::is_none")]
pub monitoring: Option<OtlpConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub manager_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deployment_token: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub native_image_host: Option<String>,
}
pub const ALIEN_SYSTEM_RESOURCE_ATTRIBUTE: &str = "alien.system";
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct OtlpConfig {
pub logs_endpoint: String,
pub logs_auth_header: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metrics_endpoint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metrics_auth_header: Option<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub resource_attributes: HashMap<String, String>,
}
#[cfg(test)]
mod input_values_tests {
use super::*;
#[test]
fn input_values_default_to_empty_and_stay_off_the_wire() {
let json = serde_json::json!({
"stackSettings": serde_json::to_value(crate::StackSettings::default()).unwrap(),
"environmentVariables": {
"variables": [],
"hash": "hash",
"createdAt": "2026-01-01T00:00:00Z",
},
"externalBindings": {},
});
let config: DeploymentConfig =
serde_json::from_value(json).expect("old shape deserializes");
assert!(config.input_values.is_empty());
let round = serde_json::to_value(&config).expect("serializes");
assert!(
round.get("inputValues").is_none(),
"empty map must not serialize"
);
}
}