use crate::api::build_status::{BuildStatusState, TestResults};
use crate::api::Api;
use crate::client::{ApiRequest, ApiResponse, Client};
use chrono::{serde::ts_seconds_option, DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BuildStatusPostPayload {
pub key: String,
pub state: BuildStatusState,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub build_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", with = "ts_seconds_option")]
pub date_added: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "ref")]
pub reference: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_results: Option<TestResults>,
}
#[derive(Debug)]
pub struct BuildStatusPost {
client: Client,
project_key: String,
commit_id: String,
repository_slug: String,
build_status: BuildStatusPostPayload,
}
impl ApiRequest for BuildStatusPost {
type Output = ();
async fn send(&self) -> ApiResponse<Self::Output> {
let request_uri = format!(
"api/latest/projects/{}/repos/{}/commits/{}/builds",
self.project_key, self.repository_slug, self.commit_id
);
self.client
.post::<Self>(
&request_uri,
&serde_json::to_string(&self.build_status).unwrap(),
)
.await
}
}
impl Api {
pub fn build_status_post(
self,
project_key: &str,
repository_slug: &str,
commit_id: &str,
build_status: &BuildStatusPostPayload
) -> BuildStatusPost {
BuildStatusPost {
client: self.client,
project_key: project_key.to_owned(),
commit_id: commit_id.to_owned(),
repository_slug: repository_slug.to_owned(),
build_status: build_status.to_owned()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_can_serialize() {
let build_status = BuildStatusPostPayload {
key: "KEY".to_string(),
state: BuildStatusState::Successful,
url: "URL".to_string(),
build_number: Some("1".to_string()),
date_added: Some(
chrono::DateTime::parse_from_rfc3339("2025-01-30T01:02:03Z")
.unwrap()
.with_timezone(&Utc),
),
description: Some("DESCRIPTION".to_string()),
duration: Some(12),
name: Some("NAME".to_string()),
parent: Some("PARENT".to_string()),
reference: Some("REF".to_string()),
test_results: Some(TestResults {
failed: 2,
successful: 3,
skipped: 1,
}),
};
let json = serde_json::to_string(&build_status).unwrap();
assert_eq!(
json,
r#"{"key":"KEY","state":"SUCCESSFUL","url":"URL","buildNumber":"1","dateAdded":1738198923,"description":"DESCRIPTION","duration":12,"name":"NAME","parent":"PARENT","ref":"REF","testResults":{"failed":2,"successful":3,"skipped":1}}"#
);
}
#[test]
fn it_can_serialize_partially() {
let build_status = BuildStatusPostPayload {
key: "KEY".to_string(),
state: BuildStatusState::Successful,
url: "URL".to_string(),
build_number: None,
date_added: None,
description: None,
duration: None,
name: None,
parent: None,
reference: None,
test_results: None,
};
let json = serde_json::to_string(&build_status).unwrap();
assert_eq!(json, r#"{"key":"KEY","state":"SUCCESSFUL","url":"URL"}"#);
} }