use anyhow::{anyhow, Result};
use serde::Deserialize;
use crate::client::{AppStoreConnectClient, AscListResponse, AscResponse, BASE_URL};
#[derive(Debug, Deserialize, Clone)]
pub struct BuildData {
pub id: String,
#[serde(rename = "type")]
pub data_type: String,
pub attributes: BuildAttributes,
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct BuildAttributes {
pub version: Option<String>,
pub uploaded_date: Option<String>,
pub expiration_date: Option<String>,
pub processing_state: Option<String>,
pub build_audience_type: Option<String>,
pub min_os_version: Option<String>,
pub icon_asset_token: Option<serde_json::Value>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct PreReleaseVersionData {
pub id: String,
#[serde(rename = "type")]
pub data_type: String,
pub attributes: PreReleaseVersionAttributes,
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PreReleaseVersionAttributes {
pub version: Option<String>,
pub platform: Option<String>,
}
impl AppStoreConnectClient {
pub async fn list_builds(&self, app_id: &str, limit: Option<u32>) -> Result<Vec<BuildData>> {
let token = self.generate_token()?;
let limit = limit.unwrap_or(10);
let url = format!(
"{}/builds?filter[app]={}&sort=-uploadedDate&limit={}",
BASE_URL, app_id, limit
);
let response = self.client
.get(&url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await
.map_err(|e| anyhow!("Failed to list builds: {}", e))?;
let status = response.status();
if status.is_success() {
let result: AscListResponse<BuildData> = response.json().await
.map_err(|e| anyhow!("Failed to parse builds response: {}", e))?;
Ok(result.data)
} else {
let error_body = response.text().await.unwrap_or_default();
Err(anyhow!("{}", Self::parse_error(status, &error_body)))
}
}
pub async fn get_build(&self, build_id: &str) -> Result<BuildData> {
let token = self.generate_token()?;
let url = format!("{}/builds/{}", BASE_URL, build_id);
let response = self.client
.get(&url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await
.map_err(|e| anyhow!("Failed to get build: {}", e))?;
let status = response.status();
if status.is_success() {
let result: AscResponse<BuildData> = response.json().await
.map_err(|e| anyhow!("Failed to parse build response: {}", e))?;
Ok(result.data)
} else {
let error_body = response.text().await.unwrap_or_default();
Err(anyhow!("{}", Self::parse_error(status, &error_body)))
}
}
pub async fn list_prerelease_versions(&self, app_id: &str) -> Result<Vec<PreReleaseVersionData>> {
let token = self.generate_token()?;
let url = format!(
"{}/preReleaseVersions?filter[app]={}&sort=-version",
BASE_URL, app_id
);
let response = self.client
.get(&url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await
.map_err(|e| anyhow!("Failed to list pre-release versions: {}", e))?;
let status = response.status();
if status.is_success() {
let result: AscListResponse<PreReleaseVersionData> = response.json().await
.map_err(|e| anyhow!("Failed to parse pre-release versions response: {}", e))?;
Ok(result.data)
} else {
let error_body = response.text().await.unwrap_or_default();
Err(anyhow!("{}", Self::parse_error(status, &error_body)))
}
}
}